• 【CF1469E】A Bit Similar


    题目

    题目链接:https://codeforces.com/problemset/problem/1469/E
    定义两个长度均为 (k) 的 01 串 (s,t) 是相似的,当且仅当存在一个 (iin[1,k]),使得 (s_i=t_i)
    给定一个长度为 (n) 的 01 串 (s),求一个长度为 (k) 的 01 串 (t),使得 (t)(s) 所有长度为 (k) 的子串都是相似的。如果有多个解,输出字典序最小的。
    多测。
    (sum nleq 10^6)(kleq n)

    思路

    等价于把 (s) 按位取反,然后求一个字典序最小的长度为 (k) 的 01 串 (t),使得 (t) 不为 (s) 的子串。
    因为要字典序最小,那么从前往后依次考虑每一位能不能取 (0)。假设已经确定了前 (i-1) 位,那么第 (i) 位能取 (0) 当且仅当:设 01 串 (t'=)(i-1) 位的 01 串 + 0,对于 (t')(s) 所有位置出现的子串,其后面 (k-i) 位,所形成的 01 串集合,大小小于 (2^{k-i})。否则如果这一位选 (0),后面无论怎么选都肯定是 (s) 的子串了。
    (s) 长度为 (k) 的子串数量有 (n-k+1) 个,也就是当 (i>log n) 的时候,这一位一定可以选 (0)
    那么只需要对最后 (20) 位分别处理即可。时间复杂度 (O(n imes max(k,log n)))

    代码

    #include <bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    const int N=(1<<20)+50;
    int n,m,T,a[N],c[N],b[N];
    ll tot,v[N];
    
    bool check()
    {
    	if (m>20) return 1;
    	int cnt=0;
    	for (int i=1;i<=n-m+1;i++)
    		if (v[b[i]]!=T) v[b[i]]=T,cnt++;
    	if (cnt==(1<<m)) return 0;
    	return 1;
    }
    
    void Work()
    {
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%1d",&a[i]);
    		c[i]=c[i-1]+a[i]; b[i]=0;
    	}
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=min(m,20);j++)
    			b[i]=(b[i]<<1)|a[i+j-1];
    	if (!check()) { cout<<"NO
    "; return; }
    	cout<<"YES
    ";
    	for (int i=21;i<=m;i++) putchar(48);
    	int k=max(0,m-20),s=0;
    	m=min(m,20);
    	for (int i=m;i>=1;i--)
    	{
    		int cnt=0; tot++;
    		for (int j=k+1;j<=n-m+1;j++)
    		{
    			if (c[j-1]-c[j-k-1]!=k) continue;
    			if ((b[j]>>(i-1))!=(s<<1)+1) continue;
    			int val=(b[j]&((1<<i-1)-1));
    			if (v[val]!=tot) v[val]=tot,cnt++;
    		}
    		if (cnt==(1<<i-1)) s=(s<<1),putchar(49);
    			else s=(s<<1)|1,putchar(48); 
    	}
    	cout<<"
    ";
    }
    
    int main()
    {
    	memset(v,-1,sizeof(v));
    	scanf("%d",&T); tot=T+1;
    	while (T--) Work();
    	return 0;
    }
    
  • 相关阅读:
    xCode中怎样保存自己的代码块
    2015-03-13---抽象工厂(附代码),
    java nio 缓冲区(一)
    MFC获取各个窗体(体)之间的指针(对象)
    自己动手写神经网络,自己真的能够动手写神经网络嘛?
    Android招財进宝手势password的实现
    QQ三方登录
    UVA 10561
    Vagi单点登录1.0
    《反脆弱》:软件业现成的鲁棒性(Robust)换了个说法变成了作者的发明,按作者的理论推导出许多可笑愚蠢的原则来
  • 原文地址:https://www.cnblogs.com/stoorz/p/15250480.html
Copyright © 2020-2023  润新知