本文主要是介绍【bzoj1025】【SCOI2009】【游戏】【dp】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
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。
Output
包含一个整数,可能的排数。
Sample Input
3
【输入样例二】
10
Sample Output
3
【输出样例二】
16
HINT
【数据规模和约定】
100%的数据,满足 1 <= N <= 1000 。
题解:首先可以发现这个变换是由几个子集合的轮换构成的。然后最后答案就是这几个轮换长度的最小公倍数+1
然后轮换长度是从1-n的。那问题就变成了把n分成几个部分,然后这几个部分的最小公倍数的种类数。
最小公倍数肯定就是一坨素因子加加乘乘。那么算出1-n有多少素因子。设f[i][j]表示用前i个素因子容量为j。直接背包好了。。
#include<iostream>
#include<cstdio>
using namespace std;
int n,t,p[1001];
long long ans,f[1001][1001];
bool ff[1001];
void get()
{for(int i=2;i<=1000;i++){if(!ff[i])p[++t]=i;for(int j=1;j<=t&&i*p[j]<=1000;j++){ff[i*p[j]]=true;if(i%p[j]==0 )break; }}
}
void dp()
{f[0][0]=1;for(int i=1;i<=t;i++){for(int j=0;j<=n;j++)f[i][j]=f[i-1][j];for(int j=p[i];j<=n;j*=p[i])for(int k=0;k<=n-j;k++)f[i][k+j]+=f[i-1][k];}
}
int main()
{cin>>n; get();dp();for(int i=0;i<=n;i++)ans+=f[t][i];cout<<ans<<endl;
}
这篇关于【bzoj1025】【SCOI2009】【游戏】【dp】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!