BZOJ1025
1025: [SCOI2009]游戏
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2315 Solved: 1510
[Submit][Status][Discuss]
Description
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想知道,对于所有可能的对应关系,有多少种可
能的排数。
Input
包含一个整数N,1 <= N <= 1000
Output
包含一个整数,可能的排数。
Sample Input
【输入样例一】
3
【输入样例二】
10
3
【输入样例二】
10
Sample Output
【输出样例一】
3
【输出样例二】
16
3
【输出样例二】
16
这道题大致是这样的:
转换其实就是n个转换关系,这n个转换关系组成了m个环(m<=n) 然后每种转换的排的个数显然就是1+LCM(size[1],.....size[m]) ,令LCM(....)为ans //size[i]是第i个环的大小。
问题就变成了a1+a2+a3+a4...+am=n,求LCM(a1,a2,a3....am)的个数。
又因为每个数字都能表示成p1^a1+p2^a2+p3^a3...这样的形式(p是素数)。
则对任意p1^b1+p2^b2+p3^b3+p4^b4..+pm^bm<=n,都有一个ans=p1^b1*p2^b2*....*pm^bm;
注意原来是等于n现在变成小于等于n,其实也比较好理解,因为有环大小为1的存在,将其不计入那么就出现小于n的情况了,而恰好不计入大小为1的环对答案没有什么影响。不能是大于n,否则所有环的大小加一起必定会大于n,与条件就不符合了。
然后就是有一个让我费解的地方了:1.对于不同的n,只要得到这个n的方式不一样(由各种素数),那么ans的种类数cont就加一。2:并且不同的n之间不会出现重叠。//这个地方我暂时还不会证明。
//http://hzwer.com/4397.html 代码来源
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int n,tot,pri[1005]; ll ans,f[1005][1005]; bool mark[1005]; void getpri(){ for(int i=2;i<=1000;++i) { if(!mark[i]) pri[++tot]=i; for(int j=1;j<=tot&&i*pri[j]<=1000;++j) { mark[i*pri[j]]=1; if(i%pri[j]==0) break; } } } void solve(){ f[0][0]=1; for(int i=1;i<=tot;++i){ for(int j=0;j<=n;++j) f[i][j]=f[i-1][j]; for(int j=pri[i];j<=n;j*=pri[i]) for(int k=0;k<=n-j;++k) f[i][k+j]+=f[i-1][k]; } for(int i=0;i<=n;++i) ans+=f[tot][i]; } int main() { scanf("%d",&n); getpri(); solve(); printf("%lld\n",ans); }
另外抄一个打表大佬的打表
http://blog.csdn.net/jiangshibiao/article/details/23040315
#include<cstdio> #include<cstring> using namespace std; const int N=1005; int t[N],a[N],nn,n,ans; bool p[N*100],f[N]; void count() { for (int i=1;i<=n;i++) t[i]=i; bool flag=true;int cnt=0; while (flag) { cnt++; flag=false; for (int i=1;i<=n;i++) { t[i]=a[t[i]]; if (t[i]!=i) flag=true; } } if (!p[cnt]) ans++,p[cnt]=true; } void solve(int sta) { if (sta==n+1) count(); for (int i=1;i<=n;i++) if (!f[i]) { f[i]=true; a[sta]=i; solve(sta+1); f[i]=false; } } int main() { scanf("%d",&nn); for (n=1;n<=nn;n++) { ans=0; memset(p,0,sizeof(p)); memset(f,0,sizeof(f)); solve(1); printf("%d ",ans); } return 0; }