题意:求选中若干个数,满足和为S,且不能选中下表i, j 和选中k, l的情况总数量。
思路:DP[i][j][k][l] i:前i个和为j,选中k个和不选中l个的情况数量,那么我们的转换应该是在必选/必不选中扩展,还有就是可以都不用,和最多不超过2个选和不选。然后由于i、j之间可以互换位置,k、l之间也可以互换位置所以结果需要乘以4.
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e3 + 7; const int maxm = 1e6 + 7; const int mod = 1e9 + 7; unsigned dp[maxn][maxn][3][3]; int a[maxn]; int main(){ int T, n, s;scanf("%d", &T); while(T --) { scanf("%d%d", &n, &s); for(int i = 1; i <= n; i ++) scanf("%d", &a[i]); memset(dp, 0, sizeof(dp)); dp[1][a[1]][0][0] = 1; dp[1][a[1]][1][0] = 1; dp[1][0][0][0] = 1; dp[1][0][0][1] = 1; for(int i = 2; i <= n; i ++){ for(int j = 0; j <= s; j ++) { int tmp = j + a[i]; if(tmp <= s) for(int k = 0; k <= 2; k ++){ dp[i][tmp][0][k] = (dp[i][tmp][0][k] + dp[i - 1][j][0][k]) % mod; dp[i][tmp][1][k] = (dp[i][tmp][1][k] + dp[i - 1][j][0][k]) % mod; dp[i][tmp][1][k] = (dp[i][tmp][1][k] + dp[i - 1][j][1][k]) % mod; dp[i][tmp][2][k] = (dp[i][tmp][2][k] + dp[i - 1][j][1][k]) % mod; dp[i][tmp][2][k] = (dp[i][tmp][2][k] + dp[i - 1][j][2][k]) % mod; } for(int k = 0; k <= 2; k ++){ dp[i][j][k][0] = (dp[i][j][k][0] + dp[i - 1][j][k][0]) % mod; dp[i][j][k][1] = (dp[i][j][k][1] + dp[i - 1][j][k][0]) % mod; dp[i][j][k][1] = (dp[i][j][k][1] + dp[i - 1][j][k][1]) % mod; dp[i][j][k][2] = (dp[i][j][k][2] + dp[i - 1][j][k][1]) % mod; dp[i][j][k][2] = (dp[i][j][k][2] + dp[i - 1][j][k][2]) % mod; } } } long long ans = 0; for(int i = 0; i <= s; i ++) ans = (ans + dp[n][i][2][2]) % mod; printf("%lld ", ans * 4LL % mod); } return 0; }