2020牛客暑期多校训练营Basic Gcd Problem(数论,快速幂)

Basic Gcd Problem

题目描述

2020牛客暑期多校训练营Basic Gcd Problem(数论,快速幂)_第1张图片

输入描述:

2020牛客暑期多校训练营Basic Gcd Problem(数论,快速幂)_第2张图片

输出描述:

在这里插入图片描述

示例1

输入

2
3 3
10 5

输出

3
25

题目大意

给定n,c。求函数fc(n)的值mod1e9+7(老操作了

若n不为1,则fc(n)=max{c*fc(gcd(i,n))},i是1~n-1的任意数;
否则,fc(n)=1;

分析

分析一下递推式可以发现,函数的值是由c的累乘得到,迭代了a层,结果就是ca%mod。
看到这里就想到用ksm了吧。

其次,这个递推不是很简单,要取个max。真暴力枚举的话肯定是不行的,T到飞起。上面已经分析了,函数值是和迭代次数有关,迭代次数越多,值就越大。因此对于c*fc(gcd(i,n))中,fc(gcd(i,n))的迭代次数要尽可能多,也就是说,gcd(i,n)的因子越多越好。所以对于原数n,进行质因数分解,每次gcd只消耗掉一个质因数。

还有一个更好的方式,就是gcd直接取n的最大因子。比如8就取4,27就取9。可以发现,实质是一样的,都尽力地使gcd的因子多。因为这种筛法比较便捷,所以后文中我采取了这种写法。

这样写应该就已经能过了(其实我也没试过,反正不是比赛,TLE有益身心健康),但是有多组数据,于是自然用到记忆化。直接怼一个数组存储我当前算出来的函数的迭代次数(注意是迭代次数而不是值,应为值还和c有关,不能很好地记忆),如果下一个小于最大的,那么就可以直接取记忆下的次数进行ksm了。

这题没有什么WAWA点,我们队也是一次过。(但是后来好像就没怎么能做出来了

代码

#include 
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int MAXN=1e6+10;
ll T,n,c,num=1,dp[MAXN],sum[MAXN];
int dv[MAXN];//最大因子 
ll ksm(ll x,ll y){
    ll ret=1;
    while(y){
        if(y&1) ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ret;
}//快速幂,这个应该都会 
int main()
{
    for(int i=2;i<=MAXN;i++) if(!dv[i]) for(int j=i;j<=MAXN;j+=i) dv[j]=max(dv[j],j/i);
    //筛最大因子,有更好的筛法欢迎指正 
    dp[1]=1,sum[1]=0;//记忆化的边界 
    for(scanf("%lld",&T);T--;){
        scanf("%lld%lld",&n,&c);
        if(n<=num) printf("%lld\n",dp[n]*ksm(c,sum[n]));//已经记忆,则直接出答案 
        else{
            for(int i=num+1;i<=n;i++) dp[i]=dp[dv[i]],sum[i]=sum[dv[i]]+1;//用类似与dp的方式推到n 
            num=n;//更新最大历史记忆 
			printf("%lld\n",dp[n]*ksm(c,sum[n]));//输出 
        }
    }
}

END

令人伤心的第四场,一小时内AC2题,4小时做H愣是没肝出来。
如果有错,欢迎指正。

你可能感兴趣的:(2020牛客多校)