1025 [SCOI2009]游戏(置换群,DP)

http://www.lydsy.com/JudgeOnline/problem.php?id=1025

【题意】

给定n,问1..n在不同的置换下变回原序列需要的不同排数有多少种。

【思路】

对于一个置换,如果分解后的到的循环长度为

A1,A2,A3…

则答案为lcm(A1,A2…)的不同种数,即有多少个不同的lcm满足:

A1+A2+A3+…=n

lcm=lcm(A1,A2,A3…)

对于A[1..]的lcm,

lcm=a1^max{p1}*a2^max{p2}..

因为很多情况会产生相同的lcm,所以只考虑max{pi},因为max不同则lcm一定不同,即问题转化为求方案数满足:

a1^max{p1}*a2^max{p2}<=n

  设f[i][j]表示前i个质数和为j的方案,则有:

f[i][j]=f[i-1][j]+sigma{ f[i-1][j-p[i]^k] }

  则答案为sigma{ f[tot][i] }

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000;
int n;
int prime[N],tot;
bool isprime[N+1];
void init()
{
memset(isprime,true,sizeof(isprime));
for(int i=2;i<=n;i++)
{
if(isprime[i]) prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<=n;j++)
{
isprime[i*prime[j]]=false;
if(i%prime[j]==0) break;
}
}
}
long long f[200][N+1];
int main()
{
scanf("%d",&n);
init();
for(int i=0;i<=tot;i++)
f[i][0]=1;
for(int i=1;i<=n;i++)
f[0][i]=1;
for(int i=1;i<=tot;i++)
for(int j=1;j<=n;j++)
{
f[i][j]=f[i-1][j];
for(int k=prime[i];k<=j;k*=prime[i])
f[i][j]+=f[i-1][j-k];
}
printf("%lld",f[tot][n]);
return 0;
}

原文地址:https://www.cnblogs.com/cutemush/p/12133940.html