2021 某谷某计划后期测试 #4 T1

题目就不说了,免得侵权 (虽然好像是搬的)

个人认为是一道非常有意思的思维题
正解是 O ( ∑ i = 0 log ⁡ n n 2 i ) = O ( n ) \mathcal O(\sum\limits_{i=0}^{\log n}\frac{n}{2^i})= \mathcal O(n) O(i=0logn2in)=O(n),这里讲一个 O ( n log ⁡ log ⁡ n ) \mathcal O(n \log \log n) O(nloglogn) 的方法

首先,本题答案一定 ≤ log ⁡ n + 1 \le \log n+1 logn+1
因为给出的串中最多只能找到 n n n 个不同的长度为 ( log ⁡ n ) + 1 (\log n)+1 (logn)+1 的串。又因为 n < 2 ( log ⁡ n ) + 1 n<2^{(\log n)+1} n<2(logn)+1,所以 ( log ⁡ n ) + 1 (\log n)+1 (logn)+1 一定是可行方案。

那么,我们就只需要在 ≤ log ⁡ n \le \log n logn 的范围内寻找答案就可以了

然后,我们还可以发现答案具有可二分性
假设已知一个在原串中没有出现的,长度为 x x x 的串。那么,只要在该串的开头或末尾加上一个 0 / 1 0/1 0/1,就构造出了一个长度为 x + 1 x+1 x+1 的满足条件的串,同理可一直往后推,从而证明了答案的单调性
所以,可以直接在 log ⁡ n \log n logn 的范围内二分 + O ( n ) \mathcal O(n) O(n) check。最后求出答案长度后,可以用线性时间求出字典序最小的答案串。总时间复杂度 O ( n log ⁡ log ⁡ n ) \mathcal O(n \log \log n) O(nloglogn)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int Maxn=16777216+20;
char s[Maxn];
bool a[Maxn];
int c[Maxn];
int n,m,cnt;
bool check(int len)
{
    
    
    int cur=0,ret=0;
    for(int i=1;i<=len;++i)
    cur=(cur<<1)|a[i];
    ++c[cur];
    if(c[cur]==1)++ret;
    for(int i=len+1;i<=n;++i)
    {
    
    
        cur^=(a[i-len]<<(len-1));
        cur=(cur<<1)|a[i];
        ++c[cur];
        if(c[cur]==1)++ret;
    }
    fill(c,c+1+(1<<len),0);
    if(ret==(1<<len))return 0;
    return 1;
}
int main()
{
    
    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;++i)
    if(s[i]=='1')a[i]=1;
    if(n==1)
    {
    
    
        if(a[1])puts("0");
        else puts("1");
        return 0;
    }
    m=log2(n)+1;
    int l=1,r=m;
    while(l<r)
    {
    
    
        int mid=(l+r)>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    int len=l;
    int cur=0;
    for(int i=1;i<=len;++i)
    cur=(cur<<1)|a[i];
    c[cur]|=1;
    for(int i=len+1;i<=n;++i)
    {
    
    
        cur^=(a[i-len]<<(len-1));
        cur=(cur<<1)|a[i];
        c[cur]|=1;
    }
    for(int x=0;x<(1<<len);++x)
    if(!c[x])
    {
    
    
        for(int i=len-1;i>=0;--i)
        if((x>>i) & 1)putchar('1');
        else putchar('0');
        putchar('\n');
        return 0;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Brian_Pan_/article/details/114033520