卧薪尝胆,厚积薄发。
神在夏至祭降下了神谕
Date: Sun Oct 28 08:11:46 CST 2018
In Category:
NoCategory
Description:
给一个
$01$
序列,问有多少种划分方式使得每段
$0$
和
$1$
个数相差不超过
$k$
。
$1\leqslant n\leqslant 10^5$
Solution:
设
$f[i]$
表示划分前
$i$
个的方案数,转移为:
$$
f[i]=\sum_{j=1}^{i-1}f[j](|s_0[i,j]-s_1[i,j]|\leqslant k)
$$
直接做是
$O(n^2)$
的,设
$d[i][j]=s_0[i,j]-s_1[i,j]$
,发现每次往后一位,对于所有
$d[i][j]$
都会增大或减小一,那么就可以不移动
$d[i][j]$
而是移动原点,即每次
$+1$
原点就相对减一,否则加一,每次把当前这个
$f$
插入到原点位置即可。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
inline int rd()
{
register int res = 0,f = 1;
register char c = getchar();
while(!isdigit(c))
{
if(c == '-')f = -1;
c = getchar();
}
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res * f;
}
int n,k;
#define MAXN 100010
#define MOD 1000000007
int a[MAXN];
int c[MAXN * 3];
int lowbit(int x){return x & (-x);}
void add(int p,int x){for(int i = p;i <= n + MAXN * 2;i += lowbit(i))c[i] = (c[i] + x) % MOD;return;}
int query(int p){int res = 0;for(int i = p;i >= 1;i -= lowbit(i))res = (res + c[i]) % MOD;return res;}
int f[MAXN];
int main()
{
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;++i)a[i] = rd();
int cur = 0;
add(cur + MAXN,1);
for(int i = 1;i <= n;++i)
{
if(a[i] == 1)--cur;
else ++cur;
f[i] = (query(min(cur + k + MAXN,3 * MAXN)) - query(max(0,cur - k - 1 + MAXN)) + MOD) % MOD;
add(cur + MAXN,f[i]);
}
cout << f[n] << endl;
return 0;
}
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡