题解 图案

传送门

真·全场唯一没做出来 T1 的人

发现这个 \(k\) 是定值,十分奇怪
那么枚举 \(|AB|\) 的长度,暴力 hash 向后判 \(k\)
这样是 \(O(n\ln n)\)
那么再向后二分合法的 \(B\) 的最长长度,覆盖即可
复杂度 \(O(n\ln n+n\log n)\)


其实赛时思路稍微拓展一下也是可以做的
\(n^2\) 暴力是跳 nxt
发现跳 nxt 时得到的结果是单调的
而我们需要结果在一个区间内
于是倍增就好了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define ull unsigned long long
//#define int long long

int n, k;
char s[N];

ull h[N], pw[N];
const ull base=13131;
inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}

namespace force{
	int ans[N];
	int calc(int n) {
		// cout<<"calc: "<<n<<endl;
		int lena, lenb;
		ull hab, hb;
		for (lena=0; lena<=n; ++lena) if ((n-k*lena>=0) && (n-k*lena)%(k+1)==0) {
			hab=hb=0;
			lenb=(n-k*lena)/(k+1);
			// cout<<"lenab: "<<lena<<' '<<lenb<<endl;
			for (int i=1; i<=lenb; ++i) hb=hb*base+s[i];
			for (int i=1; i<=lena+lenb; ++i) hab=hab*base+s[i];
			int pos=1;
			for (int i=1; i<=k; ++i) {
				if (hashing(pos, pos+lena+lenb-1)!=hab) goto jump;
				pos+=lena+lenb;
			}
			if (lenb && hashing(pos, pos+lenb-1)!=hb) goto jump;
			return 1;
			jump: ;
		}
		return 0;
	}
	void solve() {
		pw[0]=1;
		for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
		for (int i=1; i<=n; ++i) h[i]=h[i-1]*base+s[i];
		for (int i=1; i<=n; ++i) ans[i]=calc(i);
		for (int i=1; i<=n; ++i) printf("%d", ans[i]);
		printf("\n");
	}
}

namespace task1{
	int nxt[N], len[N];
	bool basic[N], ans[N];
	void solve() {
		for (int i=2,j=0,t; i<=n; ++i) {
			while (j && s[i]!=s[j+1]) j=nxt[j];
			if (s[i]==s[j+1]) ++j;
			nxt[i]=j;
			t=i-j;
			if (i%t==0 && (i/t)%k==0) basic[i]=1, len[i]=i/k;
		}
		// cout<<"basic: "; for (int i=1; i<=n; ++i) cout<<basic[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) {
			if (basic[i]) ans[i]=1;
			else {
				for (int j=nxt[i]; j&&!ans[i]; j=nxt[j]) if (basic[i-j] && j<=len[i-j])
					ans[i]=1;
			}
		}
		if (k==1) for (int i=1; i<=n; ++i) printf("1");
		else for (int i=1; i<=n; ++i) printf("%d", ans[i]);
		printf("\n");
	}
}

namespace task2{
	bool ans[N];
	void solve() {
		int t=2*k;
		for (int i=1; ; ++i) {
			int l=i*t, r=min(i*t+(2*i), n);
			for (int j=l; j<=r; ++j) ans[j]=1;
			if (r==n) break;
		}
		for (int i=1; i<=n; ++i) printf("%d", ans[i]);
		printf("\n");
	}
}

namespace task{
	int ans[N];
	void solve() {
		pw[0]=1;
		for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
		for (int i=1; i<=n; ++i) h[i]=h[i-1]*base+s[i];
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			ll pos=1ll*k*i;
			int l, r, mid;
			if (pos>n) break;
			for (int j=2; j<=k; ++j) if (h[i]!=hashing(i*(j-1)+1, i*j)) goto jump;
			l=pos+1, r=min(pos+i, 1ll*n);
			while (l<=r) {
				int mid=(l+r)>>1;
				// cout<<"mid: "<<l<<' '<<r<<' '<<mid<<endl;
				if (h[mid-pos]==hashing(pos+1, mid)) l=mid+1;
				else r=mid-1;
			}
			// cout<<"lr: "<<pos-1<<' '<<l-1<<endl;
			++ans[pos], --ans[l];
			jump: ;
		}
		for (int i=1; i<=n; ++i) ans[i]+=ans[i-1];
		for (int i=1; i<=n; ++i) printf(ans[i]?"1":"0");
		printf("\n");
	}
}

signed main()
{
	freopen("pattern.in", "r", stdin);
	freopen("pattern.out", "w", stdout);

	scanf("%d%d%s", &n, &k, s+1);
	// force::solve();
	bool tag=1;
	char lst=s[1];
	for (int i=2; i<n; ++i) {
		if (lst!=s[i+1]) tag=0;
		else lst=s[i];
	}
	// if (tag && n>2500) task2::solve();
	// else task1::solve();
	task::solve();

	return 0;
}
posted @ 2022-04-02 17:09  Administrator-09  阅读(3)  评论(0编辑  收藏  举报