JZOJ5787轨道(容斥+DP)
JZOJ5787轨道
Data Constraint
数据范围
对于20%的数据 1<=n,m<=8 k<=100
对于40%的数据 1<=n<=50 1<=m<=10^6 1<=k<=10^4
对于70%的数据 1<=n<=100 1<=m<=10^9 1<=k<=10^7
对于100%的数据 1<=n<=3000 1<=m<=10^9 1<=k<=10^7
对于20%的数据 1<=n,m<=8 k<=100
对于40%的数据 1<=n<=50 1<=m<=10^6 1<=k<=10^4
对于70%的数据 1<=n<=100 1<=m<=10^9 1<=k<=10^7
对于100%的数据 1<=n<=3000 1<=m<=10^9 1<=k<=10^7
题解
模拟赛的题,然后我就GG了
设dp[i][j]为前i个数的乘积与k的gcd是k的第j个约数(且乘积除以公约数与k互质)的方案数。
然后转移方程是dp[i][j]=sigema dp[i-1][k]*dp[1][第j个约数/第k个约数是第几个约数]这里的k是一个枚举的变量。第j个约数可以整除第k个约数。
然后考虑初始化dp[1][...];
dp[1][j]代表的是和1~m中与k的gcd为k的第j个约数的数的数量。
但是枚举绝对会T。
我们其实要求的是gcd(x,k)=第j个约数(1<=x<=m)的方案数。
把公式化一下化为gcd(x.k)=1(1<=x<=m/第j个约数(向下取整)(以后称为m1))的方案数。
然后使用容斥。
怎么用容斥呢,举个例子。
设k的质因数为A,B,C
方案数为m1/1- m1/A - m1/B - m1/C + m1/(A*B) + m1/(B*C) + m1/(A*C) - m1/(A*B*C)
很简单的容斥,仔细想想就能明白。具体实现还是看代码吧。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<vector> 8 #define MOD 10007 9 using namespace std; 10 int n,m,k,fac[4001],kpri[4001],fsf[4001][4001],mp[10000001]; 11 int m1,sum; 12 int dp[3001][4001]; 13 void dfs(int cnt,int p_m,int assemble) 14 { 15 if(cnt>kpri[0]) {sum+=m1/assemble*p_m;return;} 16 dfs(cnt+1,p_m,assemble); 17 dfs(cnt+1,-p_m,assemble*kpri[cnt]); 18 } 19 int main() 20 { 21 scanf("%d%d%d",&n,&m,&k); 22 int sqtk=sqrt(k); 23 for(int i=1;i<=sqtk;i++) 24 if(k%i==0) 25 { 26 fac[++fac[0]]=i; 27 if(k/i>sqtk) fac[++fac[0]]=k/i; 28 } 29 sort(fac+1,fac+1+fac[0]); 30 int tmp=k; 31 for(int i=2;i<=sqtk;i++) 32 { 33 if(tmp==1) break; 34 if(tmp%i==0) 35 { 36 kpri[++kpri[0]]=i; 37 while(tmp%i==0) tmp/=i; 38 } 39 } 40 if(tmp!=1) kpri[++kpri[0]]=tmp; 41 sort(kpri+1,kpri+1+kpri[0]); 42 for(int i=1;i<=fac[0];i++) 43 { 44 mp[fac[i]]=i; 45 sum=0,m1=m/fac[i]; 46 dfs(1,1,1); 47 dp[1][i]=sum%MOD; 48 } 49 for(int i=1;i<=fac[0];i++){ 50 cout<<dp[1][i]<<" "; 51 } 52 cout<<endl; 53 for(int i=1;i<=fac[0];i++) 54 for(int j=1;j<=i;j++) 55 if(fac[i]%fac[j]==0) fsf[i][++fsf[i][0]]=j; 56 for(int i=2;i<=n;i++) 57 for(int j=1;j<=fac[0];j++) 58 { 59 if(fsf[j][0]==0) continue; 60 for(int k=1;k<=fsf[j][0];k++) 61 (dp[i][j]+=dp[i-1][fsf[j][k]]*dp[1][mp[fac[j]/fac[fsf[j][k]]]])%=MOD; 62 } 63 printf("%d\n",dp[n][fac[0]]); 64 return 0; 65 }