[agc012c]Tautonym Puzzle

来源:互联网 发布:网络黑客头像 编辑:程序博客网 时间:2024/05/17 22:25

前言

怎么wxh随手秒的傻逼题我看了好多眼啊。
对于这种题我感到措手不及,因为这样的题我一般只会两种方法。
一种是分离构造,将答案序列分成若干个互不相干的部分,答案是这些部分答案的和。
那么只要我能想到如何简单构造一个部分即可。
可惜我这样想长度怎么都爆。
另一种是倍增构造,但是想了好久都不知道如何不长度*2的把答案*2。
这就很GG了。
最后总结一下我的想题过程,这样的题还是朝着二进制拆分方案(有些构造题是分解质因数)去思考的,只要能构造出一个2^t即可,而且要让这些2^t加起来。
看起来是分离构造,我想了一会儿才想到怎么不分离。
确实构造弱。。

题意

构造一个长度在200以内每个元素在100以内的字符串。
使得对于其一个子序列子串,若非空且可以表示成AA的形式,ans便+1,最后ans等于S。

构造

先找到一个最大的m使得2m<=S
那么先构造一个1 2 3……m 1 2 3……m m+1 m+1
这样显然方案数为2m
然后对于每个S剩余的二进制位t,你都需要一个2t
你可以把一个从未出现的数字塞的前半部分的t后面,然后把同样的数字塞到最末尾。
你需要按位数从大到小做,以确保这些零散数字之间不形成合法字符串。
然后就行了。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;ll two[50+5],s;int a[210],b[50+5],c[210];int i,j,k,l,t,n,m,mx,tot,top,now;int main(){    //freopen("data.out","w",stdout);    scanf("%lld",&s);    two[0]=1;    fo(i,1,50) two[i]=(ll)two[i-1]*2;    mx=50;    while (two[mx]>s) mx--;    s-=two[mx];    m=mx;    tot=2*m;    now=m;    c[++top]=now+1;    c[++top]=now+1;    now++;    tot+=2;    while (s){        while (two[mx]>s) mx--;        s-=two[mx];        b[mx]=++now;        c[++top]=now;        tot+=2;    }    printf("%d\n",tot);    fo(i,0,m){        if (i) printf("%d ",i);        if (b[i]) printf("%d ",b[i]);    }    fo(i,1,m) printf("%d ",i);    fo(i,1,top) printf("%d ",c[i]);}