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);
}
标签:前缀,加入,int,ll,个数,Prefix,Subsequence,Sum
From: https://www.cnblogs.com/liyixin0514/p/18468559