[AT2363] [agc012_c] Tautonym Puzzle

题目链接

AtCoder:https://agc012.contest.atcoder.jp/tasks/agc012_c

洛谷:https://www.luogu.org/problemnew/show/AT2363

Solution

构造题...窝太菜了想不出来...

一开始想搞一个二进制拆分,一段一段的分,每段字符相同,但是这样串长是\(O(\log ^2 n)\)的,\(\rm WA\)了近一半的点...

正解很简洁,也很巧妙:

注意到\(\rm good \, string\)的性质,我们可以在串的右半段构造一个严格上升的串,在左边构造一个右边串的排列,那么方案数就是左边串的上升子序列个数。

我们从小到大往左边加字符,设空串也是一种情况,那么当前字符可以放最前面或最后面:

  • 当前字符放最前面,那么我们的方案数会\(+1​\)
  • 放最后面,方案数\(\times 2\)

那么我们可以构造\(n+1\)的每个二进制位,串长为\(O(2\log 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('\n');}

#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\n",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;
}

猜你喜欢

转载自www.cnblogs.com/hbyer/p/10707115.html