[树状数组][前缀和] Jzoj P4738 神在夏至祭降下了神谕

Description

 

Input

Output

 

Sample Input

4 1
0 0 1 1

Sample Output

5
 

Data Constraint

 

Hint

 

 

题解

  • 设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 }

 

posted @ 2018-08-21 16:21  BEYang_Z  阅读(210)  评论(0编辑  收藏  举报