bzoj 1025 [SCOI2009]游戏(置换群,DP)
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1025
【题意】
给定n,问1..n在不同的置换下变回原序列需要的不同排数有多少种。
【思路】
对于一个置换,如果分解后的到的循环长度为
A1,A2,A3…
则答案为lcm(A1,A2…)的不同种数,即有多少个不同的lcm满足:
A1+A2+A3+…=n
lcm=lcm(A1,A2,A3…)
对于A[1..]的lcm,
lcm=a1^max{p1}*a2^max{p2}..
因为很多情况会产生相同的lcm,所以只考虑max{pi},因为max不同则lcm一定不同,即问题转化为求方案数满足:
a1^max{p1}*a2^max{p2}<=n
设f[i][j]表示前i个质数和为j的方案,则有:
f[i][j]=f[i-1][j]+sigma{ f[i-1][j-p[i]^k] }
则答案为sigma{ f[tot][i] }
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 6 typedef long long ll; 7 const int N = 1e3+5; 8 9 int n; 10 int p[N],su[N],tot; ll f[N][N]; 11 12 void get_prime() 13 { 14 for(int i=2;i<=n;i++) if(!su[i]) { 15 p[++tot]=i; 16 for(int j=i*i;j<=n;j+=i) su[j]=1; 17 } 18 } 19 int main() 20 { 21 scanf("%d",&n); 22 get_prime(); 23 f[0][0]=1; 24 for(int i=1;i<=tot;i++) { 25 for(int j=0;j<=n;j++) { 26 f[i][j]=f[i-1][j]; 27 for(int k=p[i];k<=j;k*=p[i]) 28 f[i][j]+=f[i-1][j-k]; 29 } 30 } 31 ll ans=0; 32 for(int i=0;i<=n;i++) ans+=f[tot][i]; 33 printf("%lld",ans); 34 return 0; 35 }
posted on 2016-03-21 17:15 hahalidaxin 阅读(234) 评论(0) 编辑 收藏 举报