1. 程式人生 > 實用技巧 >One Theorem, One Year LightOJ - 1298(dp+尤拉函式性質)

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]); } }