看成完全背包即可。先筛一遍素数,然后枚举素数个数,在枚举价值,dp即可。
代码:
#include<cstdio> #include<iostream> using namespace std; int prime[20000]; int pre[20000],n; long long dp[50000]; inline int solve(int x){ for(int i=1;i<=x+2000;++i)prime[i]=1; for(int i=2;i<=x+2000;++i){ if(prime[i]){ for(int j=2*i;j<=x+2000;j+=i){ prime[j]=0; } } }int k=0; for(int i=2;i<=x+2000;i++) if(prime[i]) pre[++k]=i; return k; } int main(){ scanf("%d",&n); int m=solve(n); dp[0]=1; // dp[1]=1; // dp[2]=1; for(int i=1;i<=m;++i) for(int j=pre[i];j<=n;j++) dp[j]+=dp[j-pre[i]]; printf("%lld ",dp[n]); return 0; }
我们设dp[i][0]是第i位不放的方案数,dp[i][1]是第i位放的方案数,则有:
dp[i][0]=dp[i-1][0]+dp[i-1][1],第i位不放那么前面随便即可
当i<m时,dp[i][1]=dp[i-1][1]+dp[i-1][0],前面没有限制
当i=m时,dp[i][1]=dp[i-1][1]+dp[i-1][0]-1,少了一种全部都放的方案
当i>m时,dp[i][1]=dp[i-1][1]+dp[i-1][0]-dp[i-m][0],若第i位要放,则i-m中必有一位不放,减去其方案数。
代码:
#include<cstdio> #include<istream> using namespace std; typedef long long ll; ll n,m; ll dp[500][10]; int main(){ scanf("%lld%lld",&n,&m); dp[1][0]=dp[1][1]=1; for(ll i=2;i<m;i++){ dp[i][0]=dp[i-1][0]+dp[i-1][1]; dp[i][1]=dp[i-1][0]+dp[i-1][1]; }dp[m][0]=dp[m-1][0]+dp[m-1][1]; dp[m][1]=dp[m-1][0]+dp[m-1][1]-1; for(ll i=m+1;i<=n;i++){ dp[i][0]=dp[i-1][0]+dp[i-1][1]; dp[i][1]=dp[i-1][0]+dp[i-1][1]-dp[i-m][0]; } printf("%lld ",dp[n][0]+dp[n][1]); return 0; }
我们设dp[i][1]为i位数奇数个3的数量,dp[i][0]为i位数偶数个3的数量,则:
#include<cstdio>//数位dp #include<iostream> using namespace std; const int Hws=12345; int n,dp[1010][2]; int main(){ scanf("%d",&n); dp[1][1]=1; dp[1][0]=9;//1表示1位数,后面的1表示有奇数个0,0则表示有偶数个0 for(int i=2;i<=n;i++){ int k=i==n?8:9;//等于n的时候前面不能加0啊 dp[i][0]=dp[i-1][0]%Hws*k+dp[i-1][1]%Hws;//第i位有偶数个3可以从i-1位奇数个3补一个3实现 dp[i][1]=dp[i-1][1]%Hws*k+dp[i-1][0]%Hws;//也可以在前一位有偶数个3的前面补0,1,2,4,5,6,7,8,9,实现 } //第i位有奇数个3同理,但是第n位前面就不能补0了 printf("%d ",dp[n][0]%Hws); }