AtCoder Grand Contest 012 C:Tautonym Puzzle

题目传送门:https://agc012.contest.atcoder.jp/tasks/agc012_c

题目翻译

如果一个字符串是好的,那么这个字符串的前半部分和后半部分肯定一模一样。比如\(aa\)\(bubobubo\)就是好的串,而空串,\(a\)\(abcabcabc\)以及\(abba\)就不是好的。现在给你一个小于等于\(10^{12}\)的数字\(N\),要你求出一个字符串\(s\),使得这个串的\(2^{len}-1\)个子串里刚好有\(N\)个子串是好的。要求\(len\leqslant 200\)

题解

我们先钦点空串是好的,\(s=X+Y\)\(X\)\(Y\)分别是子串里只有空串是好串的字符串。假设\(c\)并没有出现在\(s\)里,我们用两种方式将\(c\)添加进\(s\)里去:

第一种:\(s'=cX+Yc\),这样的话\(s'\)的子串里好串的数量会比\(s\)里多\(1\)

第二种:\(s'=Xc+Yc\),这样的话\(s'\)的子串里好串的数量会比\(s\)的多一倍。

只需要加一和乘二两种操作就可以凑出所有的数,我们把\(N\)二进制分解一下用双端队列搞搞就可以了。

时间复杂度:\(O(logN)\)

空间复杂度:\(O(len)\)

代码如下:

#include <deque>
#include <cstdio>
using namespace std;
typedef long long ll;

int m,num;
deque<int> s1,s2;
deque<int>::iterator it;

ll read() {
    ll x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

int main() {
    ll n=read()+1;//以为空串也是好串,所以这里要加一
    for(ll i=1;i<=n;i<<=1)m++;
    for(int i=m-2;~i;i--) {//初始有一个空串是好串,m-2是n的第二高的二进制位
        s1.push_back(++num),s2.push_back(num);
        if((n>>i)&1)s1.push_front(++num),s2.push_back(num);
    }
    printf("%d\n",(int)(s1.size()+s2.size()));
    for(it=s1.begin();it!=s1.end();it++)
        printf("%d ",(*it));
    for(it=s2.begin();it!=s2.end();it++)
        printf("%d ",(*it));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AKMer/p/10043220.html