题目大意:给定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 1010 using 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; }
时间: 2024-10-11 04:58:35