首页 > 代码库 > P1025[SCOI2009]游戏

P1025[SCOI2009]游戏

windy学会了一种游戏。对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。最开始windy把数字按

顺序1,2,3,……,N写一排在纸上。然后再在这一排下面写上它们对应的数字。然后又在新的一排下面写上它们
对应的数字。如此反复,直到序列再次变为1,2,3,……,N。 
如: 1 2 3 4 5 6 对应的关系为 1->2 2->3 3->1 4->5 5->4 6->6 
windy的操作如下 
1 2 3 4 5 6 
2 3 1 5 4 6 
3 1 2 4 5 6 
1 2 3 5 4 6 
2 3 1 4 5 6 
3 1 2 5 4 6 
1 2 3 4 5 6 
这时,我们就有若干排1到N的排列,上例中有7排。现在windy想知道,对于所有可能的对应关系,有多少种可
能的排数。



乍一看好像是有关对称群的东西,但其实关系不大;

 不过我们按照群的思路思考:

一个对应关系就是一个置换群;
这个问题变成了给定一个n,
问一个n元对称群里的所有置换群,他们各自的x次方等于π0的这个x,有几种可能;
我们知道一个置换群是有许多循环构成的;
于是有:一个对应关系(置换)的所有循环的大小的最小公倍数即是该对应关系(置换)的x,然后一个对应关系(置换)的所有循环的大小的加和不能超过n;
这个东西好像可以用来check一个x;
——对于一个x,把她唯一分解,为技术分享,如果把pi换成sum后,结果小于n,则行数x合法,否则,不合法;
(这是在找LCM是x而加和最小的一组数——这组数里的每个数就是一个技术分享——然后check她的加和)
然后这个结论没有二分的性质,于是可以尝试枚举x然后check;
——事实上我一开始就写了这个,然后x可能枚举到很大,就炸了......
于是考虑递推一个方案数;
一个合法方案是指:找一组(质数的幂),其加和小于等于n;
(在原题里的意思是:一个合法方案是一个置换,她的每一个循环都是一个质数的幂,当然可以还剩下一些元素,就让他们子环,但是循环的大小和不能比n大)
由于每一个方案构成的x都不同,所以方案数就是答案;
代码:
#include<cstdio>#include<cstring>using namespace std;const int MAXN=30000001;int prime[MAXN];bool vis[MAXN];int n,cnt;long long f[200][1010];int Prime(int );int main(){    int i,j,k;    long long ans=0;    scanf("%d",&n);    cnt=Prime(n);    f[0][0]=1;    for(i=1;i<=cnt;i++)        for(j=0;j<=n;j++){            f[i][j]+=f[i-1][j];            for(k=prime[i];k<=j;k*=prime[i])                f[i][j]+=f[i-1][j-k];        }    for(i=0;i<=n;i++)        ans+=f[cnt][i];    printf("%lld",ans);    return 0;}int Prime(int n){    int cnt=0;    memset(vis,0,sizeof(vis));vis[1]=1;    for(int i=2;i<=n;i++){        if(!vis[i])        prime[++cnt]=i;        for(int j=1;j<=cnt&&i*prime[j]<=n;j++){            vis[i*prime[j]]=1;            if(i%prime[j]==0)                break;        }    }    return cnt;}

 

P1025[SCOI2009]游戏