题目链接
AtCoder:https://agc012.contest.atcoder.jp/tasks/agc012_c
洛谷:https://www.luogu.org/problemnew/show/AT2363
题目大意
洛谷好像没有翻译,窝翻译了下顺便交了一发洛谷
我们称一个字符串(x)是好的当且仅当它满足一下条件:
- (x)可以被表示为另外一个串(y)复制一遍得到,即(x=overline {yy})。
举个例子:'aa'
和'bubobubo'
是好的,'a'
,'abcabcabc'
和'abba'
不是。
现在要求一个串(s)满足下列条件,可以证明这个串存在:
-
(|s|leqslant 200)
-
字符集大小为(100),即每个字符用([1,100])的整数表示。
-
在(s)的所有的(2^{|s|})个子序列中,恰好有(N)个串是好的,其中(N)是给出的。
Solution
构造题...窝太菜了想不出来...
一开始想搞一个二进制拆分,一段一段的分,每段字符相同,但是这样串长是(O(log ^2 n))的,( m WA)了近一半的点...
正解很简洁,也很巧妙:
注意到( m good \, string)的性质,我们可以在串的右半段构造一个严格上升的串,在左边构造一个右边串的排列,那么方案数就是左边串的上升子序列个数。
我们从小到大往左边加字符,设空串也是一种情况,那么当前字符可以放最前面或最后面:
- 当前字符放最前面,那么我们的方案数会(+1)。
- 放最后面,方案数( imes 2)。
那么我们可以构造(n+1)的每个二进制位,串长为(O(2log n)),复杂度也是(O(log n))。
#include<bits/stdc++.h>
using namespace std;
#define int long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('
');}
#define lf double
#define ll long long
#define pb push_back
const int maxn = 1e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
int n;
vector<int > s,t;
signed main() {
read(n);int p=101;n++;
while(n>1) {if(n&1) t.pb(--p),n--;else s.pb(--p),n>>=1;}
int m=s.size()+t.size();printf("%lld
",m<<1);
for(int i=0;i<(int)t.size();i++) printf("%lld ",t[i]);
for(int i=s.size()-1;~i;i--) printf("%lld ",s[i]);
for(int i=100-m+1;i<=100;i++) printf("%lld ",i);
return 0;
}