主题思想 : 这题有两种主流思路: 母函数方法,和动态规划方法。
先说母函数方法,母函数方法,模拟多项式乘法,这里,有个技巧就是,利用数组下标表示多项式指数。
模拟 (1+x+x^2+x^3+x^4+…)(1+x^2+x^4+x^6+…)(1+x^3+x^6+x^9+…) 由于是n是有限制的,所以开辟n+1大小的数组,模拟乘法。
int a[maxn];
int b[maxn];
for(int i=0;i<maxn;i++) a[i]=1,b[i]=0;
for(int i=2;i<=3;i++){
for(int j=0;j<maxn;j++){
for(int k=0;j+k<maxn;k+=i){
b[j+k]+=a[j];
}
}
for(int j=0;j<maxn;j++){
a[j]=b[j];
b[j]=0;
}
}
- 动态规划,看作是完全背包问题,因为是允许重复的,所以可以看作是完全背包问题,且是没有价值的,这就简化了状态转移方程,完全背包本来的状态转移方程是
for(int i=0;i<kind;i++){
for(int v=c[i];v<=V;v++){
dp[v]=max(dp[v],dp[v-c[i]]+value[i]);
}
}
这里value[i]=0; c[i]=i; 且求得不是最大值,而是方案总数。所以最终的状态转移方程是
dp[v]=sum(dp[v],dp[v-i]); sum 表示求和操作。
动态规划代码:
void init(){
dp[0]=1;
for(int i=1;i<=3;i++){
for(int j=i;j<maxn;j++)
{
dp[j]=sum(dp[j],dp[j-i]);
}
}
}
AC代码:
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=32800;
long long sum(long long x,long long y){
long long ans=x+y;
return ans;
}
long long dp[maxn];
void init(){
dp[0]=1;
for(int i=1;i<=3;i++){
for(int j=i;j<maxn;j++)
{
dp[j]=sum(dp[j],dp[j-i]);
}
}
}
/*
mother function
*/
void mf(){
int a[maxn];
int b[maxn];
for(int i=0;i<maxn;i++) a[i]=1,b[i]=0;
for(int i=2;i<=3;i++){
for(int j=0;j<maxn;j++){
for(int k=0;j+k<maxn;k+=i){
b[j+k]+=a[j];
}
}
for(int j=0;j<maxn;j++){
a[j]=b[j];
b[j]=0;
}
}
}
int main()
{
int n;
init();
while(scanf("%d",&n)!=EOF){
printf("%d\n",dp[n]);
}
return 0;
}