CF1383E Strange Operation

一、题目

点此看题

二、解法

草你吗老子以前写得什么几把,真他吗狗屁不通,我一怒之下重构博客。

直接建 \(\tt DFA\) 来算就行了,节点就是每个位置,转移我们考虑往每个位置后面加入 \(0/1\)

如果加入 \(1\),我们直接找到下一个 \(1\) 即可。

如果加入 \(0\),如果下一个位置是 \(0\) 或者这个位置是 \(1\),那么直接找到后面第一个 \(0\),否则这个位置是一段连续 \(0\) 的末尾,考虑继续加入 \(0\) 等效为选取后面更长的一段,从那一段等长的部分开始加 \(0\),可以用单调栈来建立转移。

考虑起始节点是第一个 \(1\),可以在任意 \(1\) 处终止(这要求我们除去开头和结尾的 \(0\)),那么直接在 \(\tt DFA\) 上面计数即可,时间复杂度 \(O(n)\)

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 1000005;
const int MOD = 1e9+7;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,l,r,ans,nm[M],p[M],g[M][2],f[M];char s[M];
void add(int &x,int y) {x=(x+y)%MOD;}
signed main()
{
	scanf("%s",s+1),n=strlen(s+1);
	l=1;while(s[l]=='0') l++;
	r=n;while(s[r]=='0') r--;
	if(l>r) {printf("%d\n",n);return 0;}
	for(int i=r,ls=0;i>=l;i--)
	{
		g[i][1]=ls;
		if(s[i]=='1') ls=i;
	}
	for(int i=r,ls=0;i>=l;i--)
	{
		if(s[i+1]=='0' || s[i]=='1') g[i][0]=ls;
		if(s[i]=='0') ls=i;
	}
	for(int i=l,nw=0;i<=r;i++)
	{
		if(s[i]=='0')
		{
			nw++;
			while(m && nm[m]<nw)
				g[p[m]][0]=i,m--;
		}
		else
			p[++m]=i-1,nm[m]=nw,nw=0;
	}
	f[l]=1;
	for(int i=l;i<=r;i++)
	{
		if(s[i]=='1') add(ans,f[i]);
		for(int j=0;j<2;j++) if(g[i][j])
			add(f[g[i][j]],f[i]);
	}
	printf("%d\n",1ll*ans*l%MOD*(n-r+1)%MOD);
}
posted @ 2021-11-18 11:27  C202044zxy  阅读(112)  评论(0编辑  收藏  举报