luogu P4161 [SCOI2009]遊戲
阿新 • • 發佈:2018-10-18
依次 math 轉化 its 轉移 getch arr 整數 print 後就能表示\(s*{p_i}^k\),這樣子計算是不重不漏的,但是無法通過此題(方案數為\(long\ long\)級別)
傳送門
我們發現整個大置換中,會由若幹形如\((a_1\rightarrow a_2,a_2\rightarrow a_3,...a_{n-1}\rightarrow a_n,a_n\rightarrow a_1)\)的循環置換組成,記某個循環置換中元素個數為\(m_i\)而整個置換的循環節大小為\(lcm(m_1,m_2,...)\),那麽問題轉化成把一個數\(n\)拆成若幹整數之和,問拆出來的整數的\(lcm\)有多少種
把\([1,n]\)的質數篩出來,然後dfs,從前往後考慮質數\(p_i\),每次從剩余的數中減去\({p_i}^k\),假設某個時刻表示的數為\(s\),那麽減去\({p_i}^k\)
考慮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\n",f[n]); return 0; }
luogu P4161 [SCOI2009]遊戲