前言
怎么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]);
}