CF1383E Strange Operation 题解
Solution
shaber 题,但是又没有做出来。
我们发现这个变化相当于可以任意删掉 \(0\),\(1\) 的话只有与 \(1\) 相邻的时候可以删掉。那么相当于我们可以把一段包含 \(1\) 的段变成只包含 \(1\) 的段。
既然要对本质不同的变化串计数,那么我们可以考虑建 DFA。加 \(1\) 的话直接找后面第 \(1\) 个 \(1\) 即可。加 \(0\) 的话如果当前为 \(1\) 或者下一个就是 \(0\) 的话我们直接找下一个 \(0\) 即可。那么需要考虑的就是当前为一段连续 \(0\) 的结尾,要加 \(1\) 个 \(0\),那么我们就需要找到后面第一个 \(0\) 连续段大于当前连续段长度的当前连续短长度个 \(0\) 的下一位。因为你可以把中间的 \(1\) 跟 \(0\) 接在前面的 \(1\) 连续段之后,然后删掉,那么你就需要再取若干个 \(0\)。这个直接用个单调栈维护一下就好了。
那么相当于我们从 \(1\) 出发,再到任意一个 \(1\) 结尾即可,因为后面的部分全都可以删掉。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define mod 1000000007
#define MAXN 1000005
// char buf[1<<21],*p1=buf,*p2=buf;
// #define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
char str[MAXN];int n,m,f[MAXN],g[MAXN][2];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
return res;
}
void Add (int &a,int b){a = add (a,b);}
void Sub (int &a,int b){a = dec (a,b);}
int top,sta[MAXN],len[MAXN],edp[MAXN];
signed main(){
scanf ("%s",str + 1),n = strlen (str + 1);
int L = 1;while (str[L] == '0') ++ L;
int R = n;while (str[R] == '0') -- R;
if (L > R){write (n),putchar ('\n');return 0;}
for (Int x = R,lst = 0;x >= L;-- x){
g[x][1] = lst;
if (str[x] == '1') lst = x;
}
for (Int x = R,lst = 0;x >= L;-- x){
if (str[x] == '1' || str[x + 1] == '0') g[x][0] = lst;
if (str[x] == '0') lst = x;
}
for (Int x = L,sum = 0;x <= R;++ x){
if (str[x] == '0'){
sum ++;
while (top && len[top] < sum) g[edp[top --]][0] = x;
}
else ++ top,len[top] = sum,edp[top] = x - 1,sum = 0;
}
f[L] = 1;int ans = 0;
for (Int x = L;x <= R;++ x){
if (str[x] == '1') Add (ans,f[x]);
for (Int t = 0;t < 2;++ t) if (g[x][t]) Add (f[g[x][t]],f[x]);
}
write (mul (mul (L,n - R + 1),ans)),putchar ('\n');
return 0;
}