CSP历年复赛题-P1069 [NOIP2009 普及组] 细胞分裂

原题链接: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;
}

 

posted @ 2024-05-28 14:08  五月江城  阅读(67)  评论(0编辑  收藏  举报