题解
- 设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 }