Description

 

Input

Output

 

Sample Input

4 1
0 0 1 1

Sample Output

5
 

Data Constraint

 
做法: 设 d[i,j]表示第 i 个数到第 j 个数中 0 的个数减去 1 的个数。 设 f[i]表示第 1~i 个数分段的方案数。 则 f[i] = sigma(f[j]),|d[j+1,i]|≤K。 时间复杂度 O(N^2)。 考虑以下 i 个数: d[1,i] d[2,i] d[3,i] …… d[i,i] 我们发现,当 i 变成 i+1 时,这 i 个数要么一起+1,要么一起-1,而对于 i,要查询的 j 也就 是所有 d 的值在[-K,K]中的 f[j]。 所以可以考虑运动的相对性:把这 i 个数+1,看成查询区间向左移动一个单位,而-1 看成查询 区间向右移动一个单位。每当算出一个 f[i],就将 f[i]的值加进当前查询区间的中点即可。 可以使用线段树维护。 时间复杂度 O(N log N)
 
代码如下:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #define mo 1000000007
 5 #define LL long long
 6 #define N 2000007
 7 #define rep(i,a,b) for(int i=a;i<=b;i++)
 8 using namespace std;
 9 LL t[N],f[N/10],sum;
10 int n,k,b[N/10];
11 
12 void Update(int p,int l,int r,int ain,int x){
13     if(l==r){
14         t[p]=(t[p]+x)%mo;
15         return;
16     }
17     int mid=(l+r)>>1;
18     if(mid>=ain) Update(p<<1,l,mid,ain,x);
19     else Update(p<<1|1,mid+1,r,ain,x);
20     t[p]=(t[p<<1]+t[p<<1|1])%mo;
21     return;
22 }
23 
24 void Find(int p,int l,int r,int L,int R){
25     if(l==L&&r==R){
26         sum=(sum+t[p])%mo;
27         return;
28     }
29     int mid=(l+r)>>1;
30     if(mid>=R) Find(p<<1,l,mid,L,R);
31     else if(mid<L) Find(p<<1|1,mid+1,r,L,R);
32     else{
33         Find(p<<1,l,mid,L,mid);
34         Find(p<<1|1,mid+1,r,mid+1,R);
35     }
36     return;
37 }
38 
39 void Init(){
40     scanf("%d%d",&n,&k);
41     rep(i,1,n){
42         int x;
43         scanf("%d",&x);
44         if(x) b[i]=b[i-1]+1; else b[i]=b[i-1]-1;    
45     }
46     f[0]=1;
47     Update(1,0,2*n,n,1);
48 }
49 
50 void Work(){
51     rep(i,1,n){
52         int site=b[i]+n;
53         sum=0;
54         Find(1,0,2*n,max(0,site-k),min(2*n,site+k));
55         f[i]=sum;
56         Update(1,0,2*n,site,f[i]);
57     }
58     printf("%lld", f[n]);
59 }
60 
61 int main(){
62     Init();
63     Work();
64 }
View Code