One Theorem, One Year LightOJ - 1298(dp+欧拉函数性质)
题意:给你n和m,令x为前m个素数,一共使用n个的乘积,例如n=3,m=2,则x=2*2*3或x=2*3*3,求所有Φ(x)的和。
思路:用到了欧拉函数的性质,首先对于x为素数,Φ(x)=x-1,然后若n*m=x,则Φ(n)*Φ(n)=Φ(x)。所以我们可以求出前500个素数,然后对其进行dp。
dp[i][j]表示总共i个素数,前j个素数。因此对于dp[i][j]有两种情况,第一种为没用用到新素数,则为dp[i][j]+=dp[i-1][j]*prime[j],若用到了新素数,则为dp[i][j]+=dp[i-1][j-1]*(prime[j]-1)。
#include <bits/stdc++.h> using namespace std; #define ll long long typedef unsigned int uint; const int N = 1000010; const int maxn=1e8+5; ll mod=1e9+7; ll prime[N]; int vis[N]; int k=0; ll dp[1010][1010]; ll qpow(ll base, int n) { ll a=base; ll res=1; while (n){ if (n&1) res=(res*a)%mod; a=(a*a)%mod; n>>=1; } return res; } void init() { for(int i=2;i<=1000000;i++) { if(vis[i]==0) { prime[++k]=i; for(int j=i+i;j<=1000000;j+=i) { vis[j]=1; } } } memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i=1;i<=500;i++) { for(int j=1;j<=i;j++) { dp[i][j]=(dp[i][j]+dp[i-1][j]*prime[j]%mod)%mod; dp[i][j]=(dp[i][j]+dp[i-1][j-1]*(prime[j]-1)%mod)%mod; } } } void solve(ll n,ll m) { } int main() { int t; int u=0; init(); scanf("%d",&t); while(t--){ ll n,m; scanf("%lld%lld",&n,&m); printf("Case %d: ",++u); printf("%d\n",dp[n][m]); } }