zoukankan      html  css  js  c++  java
  • 【AtCoder Grand Contest 012C】Tautonym Puzzle [构造]

    Tautonym Puzzle

    Time Limit: 50 Sec  Memory Limit: 256 MB

    Description

      定义一个序列贡献为1,当且仅当这个序列 由两个相同的串拼接而成,比如123123。
      请构造一个序列,使得它子序列的贡献和为n。
      要求序列长度<=200,权值<=100.

    Input

      一行一个n。

    Output

      第一行为长度len,表示你构造出的序列长度。

      第二行为你构造出的序列。

    Sample Input

      7

    Sample Output

      4
      1 1 1 1

    HINT

      n <= 1e12

    Solution

      构造题到恰好为n的。一般有两种方法:
        1. 可以构造出2^n,并且每部分互不影响;
        2. 有方法添加若干元素使得原有答案*2或+1。

      我们先考虑第一种方法。
      显然我们把 n 化为二进制。并且发现连续 x 个相同的数提供的贡献为2^(x-1)-1,并且若干个连续的不影响
      这样 s 需要1+2+……+log2(n)+(log2(n) * 2)(用于补1),极限是900。不能满足条件。

      我们再考虑第二种方法。
      s<=200,权值<=100。长度有5 * log2(n)可用,权值有2 * log2(n)可用。
      先考虑这样一个问题:
        <p1,p2,…,pk>已经是一个排列了,我们在后面加上<1,2,…,k>之后的贡献是多少
      显然,此时贡献为:<p1,p2,…,pk>的上升序列的个数
      那么我们把问题转化为:构造一个上升序列个数为n的排列

      假设我们原来的排列<p1,p2,…,pk>已经x个上升序列了,现在填入k+1

      显然,在前面填一个k+1贡献会变为:x+1。完成了+1部分。
      显然,在最后填一个k+1贡献会变为:x*2+1,这里多了一个+1。怎么办呢?

      显然一开始是0,经过3次操作0*2+1=1,1*2+1=3,3*2+1=7
      假设一开始是1,经过3次操作1*2=2,2*2=4,4*2=8

      发现我们如果将初值1的话,我们每次x*=2最后再-1和原来的效果是一样的。这样就完成了*2部分。

      最后用一个递归即可。

    Code

    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<queue>
    using namespace std;
    typedef long long s64;
    
    const int ONE = 100005;
    
    int get()
    {
            int res = 1, Q = 1; char c;
            while( (c = getchar()) < 48 || c > 57)
                if(c == '-') Q = -1;
            if(Q) res = c - 48;
            while( (c = getchar()) >= 48 && c <= 57)
                res = res * 10 + c - 48;
            return res * Q;
    }
    
    s64 n;
    int now;
    deque <int> q;
    
    void Solve(s64 n)
    {
            if(n == 1) return;
            if(n & 1) Solve(n - 1), q.push_front(++now);
            else Solve(n / 2), q.push_back(++now);
    }
    
    int main()
    {
            cin >> n;
            Solve(++n);
            printf("%d
    ", now << 1);
            while(!q.empty())
                printf("%d ", q.front()), q.pop_front();
            for(int i = 1; i <= now; i++)
                printf("%d ", i);
    }
    View Code
  • 相关阅读:
    PowerToys插件扩展(类似Alfred)
    .net打独立运行环境遇到无法trim遇到的bug
    blazor wasm开发chrome插件
    将php代码部署到新浪云测试(简单方法,包含数据库的连接)
    python修改csv某一列的内容
    windows10调用libcurl
    Java动态脚本Groovy,高级啊!
    Linux 配置Git
    Java动态脚本Groovy读取配置文件
    Java动态脚本Groovy获取Bean(奇淫技巧操作)
  • 原文地址:https://www.cnblogs.com/BearChild/p/7892668.html
Copyright © 2011-2022 走看看