CSP歷年複賽題-P1069 [NOIP2009 普及組] 細胞分裂

江城伍月發表於2024-05-28

原題連結:https://www.luogu.com.cn/problem/P1069

題意解讀:一個數s代表細胞經過一天分裂的個數,則經過t天后個數為st,要計算經過幾天后能整除m1m2,也就是st % m1m2 == 0,有多個s,要計算天數最少就可以滿足條件的。

解題思路:

直接求st % m1m2顯然不可取,會超出整數最大範圍,高精度也不是好辦法。

對於這種情況,可以分解質因數

以樣例2為例:

m1 = 24, m2 = 1,m1m2 = 23*31

s = 30時,st = (21*31*51)t = 2t*3t*5t,要能整除m1m2 = 23*31, 2t>=23, 3t>=31, t至少是3,也就是max(3/1, 1/1)

s = 12時,st = (22*31)t = 22t*3t,要能整除m1m2 = 23*31,22t>=23,3t>=31, t至少是2,也就是max(3/2⌉,1/1),注意3/2上取整

再看樣例1:

m1 = 2, m2 = 1, m1m2 = 21

s = 3時,st = 31,由於m1m2 = 21的質因數中有2,而s的質因數中沒有2,所以st永遠也不可能整除21

根據上面的分析,解法就比較明確了:

1、對m1^m2分解質因數,主要是對m1分解質因數,m2乘上各個質因數的指數,作為最終的指數即可

質因數用vector<int> pm儲存,對應的指數用vector<int> px儲存。

2、再對每一個s進行處理,同樣對s分解質因數,這次用hash陣列儲存int ps[30005],

因為m1最大30000,其質因數也不超過30000,因此s的質因數超過30000的不必要關心,只看跟m1一致的質因數即可。

ps[i] = cnt存的是s的質因數i的指數為cnt。

3、對m1^m2的每一個質因數,去s的質因數里找,

如果找不到,說明s^t永遠也無法整除m1^m2;

如果能找到,就計算res = m1^m2的指數 / s的指數 ,找res最大的就是改s經過多少天能整除m1^m2

4、對求得的多個res,取最小值

5、如果每個s都無法整除m1^m2,則輸出-1

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

int n, m1, m2;
int s;
vector<int> pm; //m1^m2的質因數
vector<int> px; //prims裡每個質因數的指數
int ps[30005]; //s的質因數對應的指數
int ans = INT_MAX;

int main()
{
    cin >> n >> m1 >> m2;
    //對m1^m2分解質因數
    for(int i = 2; i * i <= m1; i++)
    {
        if(m1 % i == 0)
        {
            int cnt = 0;
            while(m1 % i == 0)
            {
                cnt++;
                m1 /= i;
            }
            pm.push_back(i);
            px.push_back(cnt * m2);
        }
    }
    if(m1 > 1) 
    {
        pm.push_back(m1);
        px.push_back(m2);
    }

    for(int i = 1; i <= n; i++)
    {
        cin >> s;
        //對每一個s分解質因數,不考慮超過m1的質因數
        memset(ps, 0, sizeof(ps)); 
        for(int j = 2; j * j <= s && j <= 30000; j++)
        {
            if(s % j == 0)
            {
                int cnt = 0;
                while(s % j == 0)
                {
                    cnt++;
                    s /= j;
                }
                ps[j] = cnt;
            }
        }
        if(s > 1 && s <= 30000) ps[s] = 1;

        int res = 0; //如果m1=1,只需要0天就可以乘除1
        bool success = true;
        //檢查m1的每個質因數
        //如果有質因數在s的質因數中不存在,表示不能滿足要求
        //如果質因數都存在,計算m1的質因數指數 / s的中相同質因數指數,向上取整,最大的結果即需要的時間
        for(int j = 0; j < pm.size(); j++)
        {
            if(ps[pm[j]] == 0) //如果有m1的質因數在s中不存在
            {
                success = false;
                break; 
            }
            else
            {
                int low = ps[pm[j]];
                int high = px[j];
                int cnt = high / low;
                if(high % low != 0) cnt++;
                res = max(res, cnt); //找每個質因數要增長天數最大的一個
            }
        }
        if(success) ans = min(ans, res); //多個時間取最小值
    }

    if(ans == INT_MAX) cout << -1;
    else cout << ans << endl;
    return 0;
}

相關文章