先说一句题外话,有谁看到的第一眼看成了某站的知名up主夏日祭?
题面
夏至祭是一场迎接祖灵于夏季归来同时祈求丰收的庆典。村里的男人会在广
场上演出冬之军跟夏之军的战争,夏之军会打倒冬之军的大将冬男,再放火将他
连山车一起烧掉。
谢尔吉斯村长已经选好了N个人参加演出,其中一些人负责演夏之军,另一
些人负责演冬之军。由于人数众多,谢尔吉斯想把这N个人分成若干个连续的
段。为了保证演出的顺利进行,每段的夏之军人数与冬之军人数之差的绝对值不
能超过K。
谢尔吉斯想知道符合条件的划分方案有多少种。由于符合条件的方案有很多,
你只要输出方案数除以1e9+7的余数。
【输入格式】
第一行两个整数N,K,意义如题目描述所示。 接下来一行N个整数,第i个整数为0表示第i个人是夏之军,1表示第i个
人是冬之军。
【输出格式】
一行一个整数,表示符合条件的方案数除以1e9+7的余数。
【样例输入】
4 1
0 0 1 1
【样例输出】
5
【样例说明】
合法的5种方案分别为:
0 0 1 1
0 0 1|1
0|0 1 1
0|0 1|1
0|0|1|1
而00|1|1不是合法的方案, 因为第一段“00”中夏之军人数为2,冬之军人数为0,人数之差的绝对值超过了K。
【数据范围】
20%的数据保证,N≤20。
50%的数据保证,N≤8000。
另有15%的数据保证,所有的人都是夏之军。
另有15%的数据保证,K=0。
100%的数据保证,1≤N≤10^5,0≤K≤N。
比较明显的,这是一道dp;
f[i]+=f[j] (i~j符合题中所说的要求);
用s[i]表示原数组的前缀和,那么符合的条件就是:abs(2*s[i]-i+2*s[j-1]-(j-1))<=k
那么设w[i]=2*s[i]-i;
显然,w[i]-k<=w[j]<=w[i]+k
发现了什么?转移的位置是一个连续区间;
这时候我们就可以使用Splay或树状数组或线段树来大力维护dp状态;
然后就可以AC掉了;
注意w[i]-k有可能是负数,所以要将数组扩大几倍防止下标出现负数;
#include <bits/stdc++.h> #pragma GCC optimize(2) #define p 1000000007 #define inc(i,a,b) for(register int i=a;i<=b;i++) using namespace std; int a[100010],sum[100010]; long long f[100010]; long long ss[100010]; int n,k; long long w[100010]; long long c[600010]; class node{ public: inline int lowbit(register int x){ return x&(-x); } void add(register int x,register long long v){ while(x<=6*n){ c[x]=(c[x]+v)%p; x+=lowbit(x); } } int query(register int x){ register long long res=0; while(x>0){ res=(res+c[x])%p; x-=lowbit(x); } return res%p; } }tree; template<class nT> inline void read(nT& x) { char c;while(c=getchar(),!isdigit(c)); x=c^48;while(c=getchar(),isdigit(c)) x=x*10+c-48; } int main() { read(n); read(k); inc(i,1,n){ read(a[i]); sum[i]=(sum[i-1]+a[i]); w[i]=2*sum[i]-i; } f[0]=1; tree.add(w[0]+2*n,1); inc(i,1,n){ long long tmp1=tree.query(w[i]+k+2*n),tmp2=tree.query(w[i]-k-1+2*n); long long tmp=((tmp1-tmp2)%p+p)%p; f[i]=tmp%p; tree.add(w[i]+2*n,f[i]); } cout<<f[n]%p; } /* 2 1 1 0 3 0 0 1 0 30 7 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 49 17 0 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 1 1 0 1 1 0 1 1 0 1 */