[树状数组][前缀和] Jzoj P4738 神在夏至祭降下了神谕
题解
- 设f[i]为前i个人的划分方案数
- f[i]=∑f[j](|sum[i]-sum[j]|<=k)
- sum可以用前缀和预处理
- 发现,如果sum[j]在[sum[i]-k,sum[i]+k]中就可以转移
- 那么就可以用树状数组来做,然后sum[i]可能为负数,c++又没有负数数组,所以要开两倍长度
代码
1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 int n,k,sum[100010],x; 5 long long sz[400010],f[100010],mo=1e9+7; 6 void insert(int x,int y) { for (x+=200000;x<=400010;x+=x&-x) sz[x]+=y; } 7 long long getsum(int x) 8 { 9 long long y=0; 10 for (x+=200000;x;x-=x&-x) y=(y+sz[x])%mo; 11 return y; 12 } 13 int main() 14 { 15 scanf("%d%d",&n,&k); 16 for (int i=1;i<=n;i++) 17 { 18 scanf("%d",&x); 19 sum[i]=x?sum[i-1]+1:sum[i-1]-1; 20 } 21 insert(0,1); 22 for (int i=1;i<=n;i++) f[i]=(getsum(sum[i]+k)-getsum(sum[i]-k-1)+mo)%mo,insert(sum[i],f[i]); 23 printf("%lld",f[n]); 24 return 0; 25 }