HDU 5800 To My Girlfriend 【DP】

题意

有n个物品,每个物品的重量是ai,求以下式子:
ni=inj=1nk=1nl=1sm=1f(i,j,k,l,m)(ijkl)
其中f(i,jk,l,m)表示在所有物品中必选i和j,且必不选k和l,重量总和为m的选法总数。

分析

设状态dp[i][j][x][y]为选到第i个数时,总重量为j,必选了x个和必不选y个的选法总数。则在这个状态上我们可以再选一个,成为一个必选的或不是一个必选的;也可以不选,成为一个必不选的或是不是一个必不选的。也就是说可以转移给 dp[i+1][j+a[i]][x+1][y], dp[i+1][j+a[i]][x][y], dp[i+1][j][x][y+1] 和 dp[i+1][j][x][y]

AC代码

//HDU 5800 To My Girlfriend
//AC 2017-1-19 09:55:33
//DP
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+100;
const int mod=1e9+7;

int n,s;
int a[maxn];
int dp[maxn][maxn][3][3];

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&s);
        for(int i=0;i<n;++i)
            scanf("%d",a+i);
        memset(dp,0,sizeof dp);
        dp[0][0][0][0]=1;
        for(int i=0;i<n;++i)
        {
            for(int j=0;j<=s;++j)
            {
                for(int x=0;x<=2;++x)
                {
                    for(int y=0;y<=2;++y)
                    {
                        if(j+a[i]<=s)
                        {
                            if(x<2)
                                dp[i+1][j+a[i]][x+1][y]=(dp[i+1][j+a[i]][x+1][y]+dp[i][j][x][y])%mod;
                            dp[i+1][j+a[i]][x][y]=(dp[i+1][j+a[i]][x][y]+dp[i][j][x][y])%mod;
                        }
                        if(y<2)
                            dp[i+1][j][x][y+1]=(dp[i+1][j][x][y+1]+dp[i][j][x][y])%mod;
                        dp[i+1][j][x][y]=(dp[i+1][j][x][y]+dp[i][j][x][y])%mod;
                    }
                }
            }
        }
        long long ans=0;
        for(int i=0;i<=s;++i)
            ans=(ans+dp[n][i][2][2])%mod;
        cout<<(ans<<2)%mod<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/DrCarlluo/p/6580575.html