一道统计类的DP
开始把题目看错了......连样例都过不了
题目的意思要求连续的子序列,然后分配正负使之和为0
然后问有多少种方法
我们就枚举子序列的最右端
这样我们考虑每个数字,它所能贡献的只是 ai -ai
然后我们用dp【i】【j】表示到第i个数的连续子序列和为j的种类数
这样的话对于第i个数,可以单独重新开始(不与之前的连在一起)
也可以与之前的连在一起
这就是两种更新策略
最后我们统计所有最右端的和
AC代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MOD = 1e9 + 7;
int dp[1100][11000];
int n, num[1100];
int main(){
scanf( "%d", &n );
for( int i = 1; i <= n; i++ ){
scanf( "%d", &num[i] );
}
memset( dp, 0, sizeof( dp ) );
for( int i = 1; i <= n; i++ ){
dp[i][5000+num[i]]++;
dp[i][5000-num[i]]++;
for( int j = 0; j <= 10000; j++ ){
if( dp[i][j] >= MOD ){
dp[i][j] -= MOD;
}
if( j + num[i] <= 10000 ){
dp[i][j] += dp[i-1][j+num[i]];
if( dp[i][j] >= MOD ){
dp[i][j] -= MOD;
}
}
if( j - num[i] >= 0 ){
dp[i][j] += dp[i-1][j-num[i]];
if( dp[i][j] >= MOD ){
dp[i][j] -= MOD;
}
}
}
}
int ans = 0;
for( int i = 1; i <= n; i++ ){
ans += dp[i][5000];
if( ans >= MOD ){
ans -= MOD;
}
}
printf( "%d\n", ans );
return 0;
}