BZOJ 1025 SCOI2009 游戏 动态规划

来源:互联网 发布:prototype1.6.0.3.js 编辑:程序博客网 时间:2024/06/06 09:26

题目大意:给定n,定义一个置换的排数为1~n的循环经过这个置换最少T次(T>0)可以回到原来的序列 求所有可能的排数的数量

将一个置换分解为一些循环,那么这个置换的排数就是这些循环的长度的最小公倍数

于是对于一个数,我们验证这个数是否是排数的方式就是将这个数分解质因数,令x=p1^a1*p2^a2*...*pk^ak,若p1^a1+p2^a2+...+pk^ak<=n,则x就是可能的排数

分组背包即可 令f[i][j]表示用前i个质数,和为j能得出的数的数量 每组的物品是pi^1~pi^ai

时间复杂度O(n/lgn*logn*n)=O(n^2)

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define M 1010using namespace std;typedef long long ll;int n,prime[M],tot;bool not_prime[M];ll f[M][M],ans;//f[i][j]表示用前i个质数,和为j能得出的数的数量 void Linear_Shaker(){int i,j;for(i=2;i<=n;i++){if(!not_prime[i])prime[++tot]=i;for(j=1;j<=tot&&prime[j]*i<=n;j++){not_prime[prime[j]*i]=1;if(i%prime[j]==0)break;}}}int Quick_Power(int x,int y){int re=1;while(y){if(y&1)re*=x;x*=x;y>>=1;}return re;}int main(){int i,j,k,temp;cin>>n;Linear_Shaker();f[0][0]=1;for(i=1;i<=tot;i++){for(j=0;j<=n;j++)f[i][j]+=f[i-1][j];for(j=prime[i];j<=n;j*=prime[i])for(k=j;k<=n;k++)f[i][k]+=f[i-1][k-j];}for(i=0;i<=n;i++)ans+=f[tot][i];cout<<ans<<endl;return 0;}


0 0