我们发现整个大置换中,会由若干形如((a_1 ightarrow a_2,a_2 ightarrow a_3,...a_{n-1} ightarrow a_n,a_n ightarrow a_1))的循环置换组成,记某个循环置换中元素个数为(m_i)而整个置换的循环节大小为(lcm(m_1,m_2,...)),那么问题转化成把一个数(n)拆成若干整数之和,问拆出来的整数的(lcm)有多少种
把([1,n])的质数筛出来,然后dfs,从前往后考虑质数(p_i),每次从剩余的数中减去({p_i}^k),假设某个时刻表示的数为(s),那么减去({p_i}^k)后就能表示(s*{p_i}^k),这样子计算是不重不漏的,但是无法通过此题(方案数为(long long)级别)
考虑dp,设(f_i)为(n=i)时的答案,然后依次枚举质数,因为当前考虑的质数之前没考虑,所以(f_i)可以从(f_{i-p_j},f_{i-{p_j}^2},f_{i-{p_j}^3}...)转移过来,这其实就是个背包
详见代码
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define eps (1e-5)
using namespace std;
il LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int prm[200],tt,n;
char vis[1010];
il void init()
{
for(int i=2;i<=n;i++)
{
if(!vis[i]) prm[++tt]=i;
for(int j=1;j<=tt&&i*prm[j]<=n;j++)
{
vis[i*prm[j]]=true;
if(i%prm[j]==0) break;
}
}
}
LL f[1010];
/*void dfs(int o,int s)
{
if(o>tt||s<prm[o]) return;
dfs(o+1,s);
int xx=prm[o];
while(s>=xx)
{
++ans;
dfs(o+1,s-xx);
xx*=prm[o];
}
}*/
int main()
{
n=rd();
init();
for(int i=0;i<=n;i++) f[i]=1;
for(int i=1;i<=tt;i++)
for(int j=n;j>=0;j--)
for(int k=prm[i];j-k>=0;k*=prm[i])
f[j]+=f[j-k];
printf("%lld
",f[n]);
return 0;
}