【题解】CF1383E Strange Operation
不难发现一次操作就是选两个位置并将它们取 or
。
然后是非常经典的操作,匹配。类似于子序列自动机。没有做过类似的可能很难想到这一点。
那么显然对于一个答案串,它的最优匹配点是唯一的,简单来说就是贪心的取最前面的。
那么我们可以定义状态 \(f[i][j]\) 表示长度为 \(i\) 的答案串,匹配到 \(s\) 的第 \(j\) 个位置。
事实上我们并不关心答案串的长度,直接保留 \(f[i]\) 表示匹配到 \(i\) 的方案数也可以不重不漏,因为和子序列自动机相同,最优匹配点不同两个子序列一定不相同。
现在只用考虑向当前串后面加上 \(0/1\) 。
加上 \(1\),最优匹配点移动到下一个 \(1\) 的位置。
当前串最后为 \(1\) 或者后面一个位置为 \(0\),那么答案串加上 \(0\) ,最优匹配点一定到下一个 \(0\) 的位置。
上面两个都不难理解,因为我们可以把连续一段 \(0/1\) 保留任意个,有 \(1\) 相邻的 \(0\) 可以随便删。
对于当前位置为 \(0\) 而后面一个位置是 \(1\),我们要给答案串也加上 \(0\) ,这时如果选择下一个 \(0\),那么两个 \(0\) 之间的 \(1\) 无法消掉。所以我们只有选择后面连续的一段 \(0\)。这可以用单调栈维护做到线性,时间复杂度 \(\mathcal{O}(N)\)。
/*
Author : SharpnessV
Right Output ! / Accepted !
*/
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = a;i <= b;i++)
#define pre(i, a, b) for(int i = a;i >= b;i--)
#define rp(i, a) for(int i = 1; i <= a; i++)
#define pr(i, a) for(int i = a; i >= 1; i--)
#define go(i, x) for(auto i : x)
#define mp make_pair
#define pb push_back
#define pf push_front
#define fi first
#define se second
#define ze(p) memset(p, 0, sizeof(p))
#define YES puts("YES")
#define NO puts("NO")
#define si(x) (int)(x).size()
using namespace std;
const double eps = 1e-15, pi = 3.1415926535897932385;
typedef long long LL;
typedef pair<int,int> Pr;
const int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1}, inf = 0x7fffffff;
//char buf[1<<22],*p1=buf,*p2=buf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(!isdigit(ch))f = ('-' == ch ? -1 : 1), ch = getchar();
while(isdigit(ch))x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
if(~f)return x;return -x;
}
int gcd(int x,int y){return y ? gcd(y, x % y) : x;}
int lcm(int x,int y){return x / gcd(x, y) * y;}
#define P 1000000007
inline void ad(int &x, int y){x += y; if(x >= P) x -= P;}
inline void su(int &x, int y){x -= y; if(x < 0) x += P;}
int Pow(int x, int y){
if(y < 0)return Pow(Pow(x, P - 2), -y);
int now = 1 ;
for(;y;y >>= 1, x = 1LL * x * x % P)if(y & 1) now = 1LL * now * x % P;
return now;
}
#define N 1000005
char s[N];int n, p[N], q[N], top, f[N], g[N][2];
int main(){
//int T = read();while(T--)solve();
scanf("%s", s + 1);
n = strlen(s + 1);
bool flag = true;
rp(i, n)flag &= s[i] == '0';
if(flag){printf("%d\n", n);return 0;}
int l = 1, r = n, k = 0;
while('0' == s[l])l++;
while('0' == s[r])r--;
pre(i, r, l){
g[i][1] = k;
if('1' == s[i])k = i;
}
k = 0;
pre(i, r, l){
if(s[i + 1] == '0' || s[i] == '1')g[i][0] = k;
if(s[i] == '0')k = i;
}
int sum = 0;
//rep(i, l, r)printf("%d ",g[i][0]);putchar('\n');
rep(i, l, r){
if(s[i] == '0'){
sum++;
while(top && p[top] < sum)g[q[top]][0] = i, top--;
}else if(sum){
p[++top] = sum, q[top] = i - 1, sum = 0;
}
}
f[l] = 1;int ans = 0;
rep(i, l, r){
if('1' == s[i])ad(ans, f[i]);
rep(x, 0, 1)if(g[i][x])
ad(f[g[i][x]], f[i]);
}
printf("%lld\n", 1LL * ans * l % P * (n - r + 1) % P);
return 0;
}