题目
一个整数n,设能够被拆成一些整数的和的方案数为ans。
求mansmans。对一个质数p取模。
这些整数没有顺序。
比如:
n,m≤200000n,m≤200000
解题思路
背包。
求一条分割线,将1~n的数划分为A组和B组,A组的用无限背包解决,B组的用有限背包解决。
那么按照n−−√n来分割。
最基本的转移:A组的按照无限背包来做,即做到数i,目前装了j的容量。
g[i][j]=g[i−1][j]+g[i][j−i]g[i][j]=g[i−1][j]+g[i][j−i]
听说还有五边形数。
B组的按照有限背包做,即序列中有i个数,目前装了j的容量。
最基本的转移:要么加n−−√+1n+1,要么序列中所有的数+1+1。
f[i][j]=f[i−1][j−n−−√−1]+f[i][j−i]f[i][j]=f[i−1][j−n−1]+f[i][j−i]
最后答案卷一下就行了。
陷阱:欧拉定理。求ans的时候模的是p-1而不是p。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 200010
#define mo 999999598
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int f[2][N],g[2][N],sum[N];
int o,n,i,j,k,l;
LL ans,m;
LL ksm(LL x,LL y,LL Mo){
LL rs=1;
for(;y;y>>=1,x=(x*x)%Mo)if(y&1)rs=(rs*x)%Mo;
return rs;
}
int main(){
scanf("%d%d",&n,&m);
l=sqrt(n);
f[0][0]=1;sum[0]=1;
fo(i,1,l){
o=1-o;
memset(f[o],0,sizeof(f[o]));
fo(j,l+1,n){
f[o][j]=(f[1-o][j-l-1]+f[o][j-i])%mo;
sum[j]=(sum[j]+f[o][j])%mo;
}
}
g[0][0]=1;
o=0;
fo(i,1,l){
o=1-o;
memset(g[o],0,sizeof(g[o]));
fo(j,0,n){
g[o][j]=g[1-o][j];
if(j>=i)g[o][j]=(g[o][j]+g[o][j-i])%mo;
}
}
fo(i,0,n)ans=(ans+((LL)g[o][i]*sum[n-i])%mo)%mo;
ans=ksm(m,ans,mo+1);
printf("%lld",ans);
return 0;
}