hdu 5185 Equation (完全背包变形)

来源:互联网 发布:ubuntu terminal 配置 编辑:程序博客网 时间:2024/06/06 18:58

题意:

给出n个数字,数字满足 x[i]<=x[i+1]<=x[i]+1;要使得这n个数的和为n,有多少种方案。

题解:

类似于完全背包,dp[i][j]以j为结尾重量为i的方案数。我们通过分析会发现对于某个重量i,数字能取到的最大值是(sqrt(8*i+1)-1)/2,根据前n项和变形而来。这样就把复杂度从O(n^2)变为O(nsqrt(n))。

转移方程 dp[i][j]=dp[i-j][j-1]+dp[i-j][j] 对于这样的重量i,以j数字为结尾任然可以再次原则j,以j-1数字为结尾肯定也可以选择j,对应的上个重量都是i-j。着里的重量其实就是多了数字的和。

#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<queue>#include<map>#include<hash_map>#include<set>using namespace std;#define B(x) (1<<(x))typedef __int64 ll;const int oo=0x3f3f3f3f;const ll OO=1LL<<61;const int MOD=10007;const int maxn=50005;const int maxm=320;int dp[maxn][maxm];int main(){    int T,n,m,mod;    scanf("%d",&T);    for(int cas=1;cas<=T;cas++){        scanf("%d %d",&n,&mod);        memset(dp,0,sizeof dp);        dp[0][0]=1;        for(int i=1;i<=n;i++){            m=(sqrt(8*i+1.0)-1.0)/2.0;            for(int j=1;j<=m;j++){                dp[i][j]=(dp[i-j][j-1]+dp[i-j][j])%mod;            }        }        int ans=0;        for(int i=1;i<=m;i++)            ans=(ans+dp[n][i])%mod;        printf("Case #%d: %d\n",cas,ans);    }    return 0;}



0 0