Subsequence and Prefix Sum
Subsequence and Prefix Sum
\(n\) 才 \(100\),\(a_i\) 才 \(20\),显然 DP。
设 \(f_{i,j}\) 表示第 \(i\) 个数,前 \(i\) 个数前缀和为 \(j\) 的方案数。
显然,\(f_{0,0}=1\)。
留意到如果 \(j=0\),那么加入和不加入第 \(i\) 个数,最终的答案序列是一样的,因此此时加入第 \(i\) 个数对答案是没有贡献的,但是加入后会对之后的前缀和产生影响,会影响之后的序列。因此 \(f_i\) 不能统计答案,而 \(f_{i+1}\) 应该统计这种情况。
我们设 \(g_k\) 表示这种情况,也就是加入 \(k\) 后前缀和为 \(k\) 的方案数。
当 \(j\ne 0\) 时,\(f_{i,j+a_i}\) 不仅要统计前一位前缀和为 \(j\) 的方案数,还应统计之前某一位没有计入答案但是对前缀和产生影响的情况,即 \(g_j\)。
转移方程如下:
- 第 \(i\) 个数不加入前缀和中:\(f_{i,j}\gets f_{i-1,j}\)
 - 第 \(i\) 个数加入前缀和中:\([j\ne 0]\ f_{i,j+a_i}\gets f_{i-1,j}+g_j\)
 - 枚举完 \(j\) 之后:\(g_{a_i}\gets f_{i-1,0}\)
 
答案即为 \(\sum_j f_{n,j}\)
因为值有负数,所以下标需要调整,注意细节。
综上,时间复杂度 \(O(n^2V)\)。
Code
#include<bits/stdc++.h>
#define sf scanf
#define pf printf
using namespace std;
typedef long long ll;
const int N=101,mod=1e9+7,M=1001;
int n,a[N],b[N];
ll dp[N][2010];
ll g[2010];
void add(ll &a,ll b){
	a=(a+b)%mod;
}
int main(){
	sf("%d",&n);
	for(int i=1;i<=n;i++){
		sf("%d",&a[i]);
		b[i]=b[i-1]+a[i];
	}
	dp[0][M]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=M<<1;j++){
			add(dp[i][j],dp[i-1][j]);
			if(j!=M){
				add(dp[i][j+a[i]],dp[i-1][j]+g[j]);
			}
		}
		g[a[i]+M]=dp[i-1][M];
	}
	ll ans=0;
	for(int i=0;i<=M<<1;i++) add(ans,dp[n][i]);
	pf("%lld\n",ans);
}
本文来自博客园,作者:wing_heart,转载请注明原文链接:https://www.cnblogs.com/wingheart/p/18468559

                
            
        
浙公网安备 33010602011771号