hdu 5800

题意:给出一个序列(1000长度),定义f(i,j,k,l,m) 为a[i],a[j]必取,a[k],a[l]必不取和为m的子集个数。统计任一i,j,k,l,m的和是多少(i!=j!=k!=l)

dp[i][j][k][l],表示前i个组成重量j,有k个必取l个必不取的方案数,当i+1则分四种情况,a[i+1]为必取,非必取,既不为必取也不为非必取讨论

#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N = 1000+10;
const int mod=1e9+7;
const double en=2.718281828459;
using namespace std;
int t,n,s,a[N];
int dp[N][N][3][3];
int main() {
 //freopen("in.txt","r",stdin);
cin>>t;
while(t--){
  scanf("%d%d",&n,&s);
  memset(dp,0,sizeof(dp));
  int i,j,s1,s2;
  for(i=1;i<=n;i++)
    scanf("%d",&a[i]);
  dp[0][0][0][0]=1;
  for(i=1;i<=n;i++)
    for(j=0;j<=s;j++)
      for(s1=0;s1<=2;s1++)
        for(s2=0;s2<=2;s2++){
          dp[i][j][s1][s2]+=dp[i-1][j][s1][s2];
          dp[i][j][s1][s2]%=mod;
          if(j>=a[i]){
            dp[i][j][s1][s2]+=dp[i-1][j-a[i]][s1][s2];
            dp[i][j][s1][s2]%=mod;
          }
          if(s2>=1){
          dp[i][j][s1][s2]+=dp[i-1][j][s1][s2-1];
          dp[i][j][s1][s2]%=mod;
          }
          if(j>=a[i]&&s1>=1){
            dp[i][j][s1][s2]+=dp[i-1][j-a[i]][s1-1][s2];
            dp[i][j][s1][s2]%=mod;
          }
        }
      ll sum=0;
      for(int i=1;i<=s;i++){
        sum+=dp[n][i][2][2];
        sum%=mod;
      }
      cout<<(sum*4)%mod<<endl;
}
}