Luogu P4161 [SCOI2009]遊戲
阿新 • • 發佈:2020-08-07
題意
定義一個長度為 \(n\) 的置換的步數為將 \(P=(1,2,\cdots,n)\) 在該置換操作下變回原樣的最小次數。
求有多少個 \(K\) 使得存在一個長度為 \(n\) 置換使得其步數為 \(K\)。
\(\texttt{Data Range:}1\leq n\leq 10^3\)
題解
類比一下這題我們可以得到如下轉移方程:
\[f_{i,j}=f_{i,j-1}+\sum\limits_{p_j^k\leq i}f_{i-p_j^k,j-1} \]
這裡不需要乘 \(p_j^k\) 的原因是我只要求出 \(K\) 有多少而不是 \(K\) 的和,然後就沒了。
程式碼
#include<bits/stdc++.h> using namespace std; typedef int ll; typedef long long int li; const ll MAXN=1e4+51; ll n,ptot; li res=1; ll prime[MAXN],np[MAXN]; li f[MAXN]; inline ll read() { register ll num=0,neg=1; register char ch=getchar(); while(!isdigit(ch)&&ch!='-') { ch=getchar(); } if(ch=='-') { neg=-1; ch=getchar(); } while(isdigit(ch)) { num=(num<<3)+(num<<1)+(ch-'0'); ch=getchar(); } return num*neg; } int main() { n=read(),f[0]=1; for(register int i=2;i<=n;i++) { if(!np[i]) { prime[++ptot]=i; } for(register int j=1;i*prime[j]<=n;j++) { np[i*prime[j]]=1; if(!(i%prime[j])) { break; } } } for(register int i=1;i<=ptot;i++) { for(register int j=n;j>=1;j--) { for(register int k=prime[i];k<=j;k*=prime[i]) { f[j]+=f[j-k]; } } } for(register int i=1;i<=n;i++) { res+=f[i]; } printf("%lld\n",res); }