思路:
DP[ i ] 代表以 i 结尾的方案数. dp[i] += sum[i] - sum[j - 1] != 0 ? dp[j] : 0 ;
对于100%的数据,满足1<=N<=105, |Ai|<=100n 1e5呀,两层for,GG;
利用树状数组维护sum[i],存的是以sum[i]的方案数 ,
那么每次加上当前所有的方案,减去sum[i]的方案,就好了。
这里还有一个小问题就是 |sum[i]|<=1e7,所以先离散化一下就好了。
把当前所有前缀和的方案数加起来。。然后减掉以自己的方案数。
也可以用map.
树状数组维护。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
const int N=1e5+10;
LL sval[N],sum[N];
LL dp[N];
int lowbit(int x)
{
return x&(-x);
}
LL Sum(int d)
{
LL ans=0;
while(d)
{
ans=(ans+sval[d])%mod;
d=d-lowbit(d);
}
return ans;
}
void add(int d,LL val,int n)
{
while(d<=n)
{
sval[d]=(sval[d]+val)%mod;
d+=lowbit(d);
}
}
vector<LL>xs;
int main()
{
LL n,a;
scanf("%lld",&n);
sum[0]=0;
xs.push_back(0);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a);
sum[i]=sum[i-1]+a;
xs.push_back(sum[i]);
}
sort(xs.begin(),xs.end());
auto it=unique(xs.begin(),xs.end());
for(int i=0;i<=n;i++)
sum[i]=lower_bound(xs.begin(),it,sum[i])-xs.begin()+1;
memset(dp,0,sizeof(dp));
for(int i=0;i<=n;i++)
{
dp[i]+=Sum(xs.size());
dp[i]-=Sum(sum[i])-Sum(sum[i]-1);
dp[i]=(dp[i]+mod)%mod;
if(dp[i]==0)
dp[i]=1;
add(sum[i],dp[i],xs.size());
}
printf("%lld
",dp[n]);
return 0;
}
map维护
#include <bits/stdc++.h> using namespace std; typedef long long LL; const LL mod=1e9+7; const int N=1e5+10; LL sum[N]; LL dp[N]; map<int,int>mp; int main() { LL n,a; scanf("%lld",&n); sum[0]=0; mp.clear(); for(int i=1;i<=n;i++) { scanf("%lld",&a); sum[i]=sum[i-1]+a; } memset(dp,0,sizeof(dp)); dp[0]=1; mp[0]=1; LL cnt=1; for(int i=1;i<=n;i++) { if(!mp.count(sum[i])) { dp[i]=cnt; mp[sum[i]]=dp[i]; } else { dp[i]=((cnt-mp[sum[i]])%mod+mod)%mod; mp[sum[i]]=(mp[sum[i]]+dp[i]+mod)%mod; } cnt=(cnt+dp[i]+mod)%mod; } printf("%lld ",dp[n]); return 0; }