题面


Sample Input

7
8
7
10
31
20
100
869120

Sample Output

6
1 1 4 5 1 4
7
1 9 1 9 8 1 0
8
1 9 4 9 1 0 0 1
8
1 9 2 6 0 8 1 7
9
9 7 3 6 5 8 4 1 2
10
0 5 9 3 6 1 4 2 7 8
72
47 45 28 9 41 50 33 61 27 15 38 54 52 22 57 7 30 12 46 21 19 8 71 20 23 6 18 26 17 39 4 53 44 3 31 68 29 42 62 37 69 67 40 65 2 55 36 35 11 49 24 25 43 48 0 1 16 10 70 66 64 32 5 51 60 63 58 56 59 13 14 34

题解

首先我们想想对于一个序列怎么算它的上升子序列个数。我们一般会用 DP ,

d

p

[

i

]

dp[i]

dp[i] 表示以 i 结尾的上升子序列个数,那么

d

p

[

i

]

=

j

=

0

i

1

[

a

j

<

a

i

]

d

p

[

j

]
  

,

d

p

[

0

]

=

1

dp[i]=\sum_{j=0}^{i-1}[a_j<a_i]dp[j]\;,dp[0]=1

dp[i]=∑j=0i−1​[aj​<ai​]dp[j],dp[0]=1,答案为

a

n

s

[

i

]

=

j

=

0

i

d

p

[

j

]

a

n

s

[

0

]

=

1

ans[i]=\sum_{j=0}^{i}dp[j],ans[0]=1

ans[i]=∑j=0i​dp[j],ans[0]=1。

考虑在序列最末端新加入一个比前面都大的数,

d

p

[

n

+

1

]

=

i

=

0

n

d

p

[

i

]

=

a

n

s

[

n

]
  

,
  

a

n

s

[

n

+

1

]

=

2

a

n

s

[

n

]

dp[n+1]=\sum_{i=0}^{n}dp[i]=ans[n]\;,\;ans[n+1]=2\cdot ans[n]

dp[n+1]=∑i=0n​dp[i]=ans[n],ans[n+1]=2⋅ans[n],因此会使得答案乘 2——左移 1。如果在序列最末端加入一个比前面 (除了位置 0) 都小的数,

d

p

[

n

+

1

]

=

d

p

[

0

]

=

1
  

,
  

a

n

s

[

n

+

1

]

=

a

n

s

[

n

]

+

1

dp[n+1]=dp[0]=1\;,\;ans[n+1]=ans[n]+1

dp[n+1]=dp[0]=1,ans[n+1]=ans[n]+1,就会使得答案+1,那么就有了一个使序列长度

<

128

<128

<128 的构造方案:

  • 从 K 的最高位开始遍历,每到下一位就在序列最后加入一个比前面都大的数。
  • 如果当前位为 1,则把序列每个位置整体加 1(答案不变),然后在序列最后加入 1。

于是我们拿到了 28 分的高分。

这个构造方法实际上序列的长度为

log

2

K

+

b

i

t

c

o

u

n

t

(

K

)

\log_2K+bitcount(K)

log2​K+bitcount(K),我们会被存在过多 1 的 K 卡到序列长度 98 以上。如果我们能近乎把每一段连续的 1 都只加入 1 个点的话,由于连续的 1 不超过

log

2

K

2

\frac{\log_2K}{2}

2log2​K​ 段,因此可以把序列长度卡到 98 以下。怎么做呢?

我们发现,实际上不可能每一段连续的 1 都只加入一个点,但是稍微把长度卡到 98 以下是可行的。

考虑之前的 DP 计算,我们在最后加入一个数 x 时,实际上是把答案增加了

i

=

0

n

[

a

i

<

x

]

d

p

[

i

]

\sum_{i=0}^{n}[a_i<x]dp[i]

∑i=0n​[ai​<x]dp[i] 这么多,如果能找到这么一个 x ,使得这个值刚好为

2

?

1

2^?-1

2?−1 不就可以优化了?

因此我们维护对于当前每一个值 x,

i

=

0

n

[

a

i

<

x

]

d

p

[

i

]

\sum_{i=0}^{n}[a_i<x]dp[i]

∑i=0n​[ai​<x]dp[i] 是多少,当我们遍历到一段连续 n 个的 1 时,就先在序列尾部加 n 个比前面都大的数让答案左移 n 位,然后把刚好

i

=

0

n

[

a

i

<

x

]

d

p

[

i

]

=

2

n

1

\sum_{i=0}^{n}[a_i<x]dp[i]=2^n-1

∑i=0n​[ai​<x]dp[i]=2n−1 的 x 加入序列尾部,最后把序列前面 ≥ x 的数都+1。这样就能比较好地优化长度了,实测拍了20000+组 T=1500 的数据,序列长度没有超过 89 的。

CODE

#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 205
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#pragma GCC optimize(2)
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 998244353;
int n,m,i,j,s,o,k;
int a[MAXN],L,hb,mx;
LL ct[MAXN];
int mp(LL x) {
for(int i = 0;i <= mx;i ++) if(ct[i] == x) return i;
return -1;
}
void addbot(int ad) {
for(int i = 1;i <= L;i ++) if(a[i] > ad) a[i] ++;
mx ++;
for(int i = mx;i > ad+1;i --) swap(ct[i],ct[i-1]);
a[++ L] = ad+1; ct[ad+1] = ct[ad];
for(int i = ad+1;i <= mx;i ++) ct[i] += ct[ad];
return ;
}
int main() {
freopen("make.in","r",stdin);
freopen("make.out","w",stdout);
int T = read();
while(T --) {
LL K = read();
L = 0;
memset(a,0,sizeof(a));
memset(ct,0,sizeof(ct));
hb = 62,mx = 0;
ct[0] = 1ll;
while(!(K & (1ll<<hb))) hb --;
for(int i = hb-1;i >= 0;i --) {
if(K & (1ll<<i)) {
LL tm = 1ll;
while(i > 0 && (K & (1ll<<(i-1)))) {
i --; tm = tm<<1ll|1ll;
}
for(LL tmp = tm;tm > 0ll;tmp = min(tmp,tm)) {
tmp = tm;
int add = 0;
while((add=mp(tmp)) < 0) tmp >>= 1ll;
LL tmc = tmp;
while(tmc > 0) {
a[++ L] = ++ mx; ct[mx] = ct[mx-1]<<1ll;
tm >>= 1ll;
tmc >>= 1ll;
}
addbot(add);
}
}
else {
a[++ L] = ++ mx;
ct[mx] = ct[mx-1]<<1ll;
}
}
printf("%d\n",L);
for(int i = 1;i <= L;i ++) printf("%d ",a[i]);
ENDL;
}
return 0;
}

造序列(构造,DP)的更多相关文章

  1. At grand 022 GCD序列构造 dp/floyd二进制变换最少费用

    A diverse words指的是每一个字母在单词中出现的次数不超过1的单词 题目要求你求出字典序比当前给定单词大的字典序最小单词 1.如果给定的单词长度小于26 就遍历一次在单词尾部加上字典序最小 ...

  2. 贪心/构造/DP 杂题选做Ⅱ

    由于换了台电脑,而我的贪心 & 构造能力依然很拉跨,所以决定再开一个坑( 前传: 贪心/构造/DP 杂题选做 u1s1 我预感还有Ⅲ(欸,这不是我在多项式Ⅱ中说过的原话吗) 24. P5912 ...

  3. 贪心/构造/DP 杂题选做Ⅲ

    颓!颓!颓!(bushi 前传: 贪心/构造/DP 杂题选做 贪心/构造/DP 杂题选做Ⅱ 51. CF758E Broken Tree 讲个笑话,这道题是 11.3 模拟赛的 T2,模拟赛里那道题的 ...

  4. 【2】【leetcode-105,106】 从前序与中序遍历序列构造二叉树,从中序与后序遍历序列构造二叉树

    105. 从前序与中序遍历序列构造二叉树 (没思路,典型记住思路好做) 根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [ ...

  5. [leetcode]从中序与后序/前序遍历序列构造二叉树

    从中序与后序遍历序列构造二叉树 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序遍历 po ...

  6. codevs 1962 马棚问题--序列型DP

    1962 马棚问题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 每天,小明和他的马外出,然后他们一边跑一边玩耍.当他们结束 ...

  7. LeetCode 中级 - 从前序与中序遍历序列构造二叉树(105)

    一个前序遍历序列和一个中序遍历序列可以确定一颗唯一的二叉树. 根据前序遍历的特点, 知前序序列(PreSequence)的首个元素(PreSequence[0])为二叉树的根(root),  然后在中 ...

  8. 括号序列的dp问题模型

    括号序列的dp问题模型 Codeforces314E ◦给定一个长度为n的仅包含左括号和问号的字符串,将问号变成左括号或 右括号使得该括号序列合法,求方案总数. ◦例如(())与()()都是合法的括号 ...

  9. [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)

    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...

  10. LeetCode106. 从中序与后序遍历序列构造二叉树

    106. 从中序与后序遍历序列构造二叉树 描述 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 示例 例如,给出 中序遍历 inorder = [9,3,15,20 ...

随机推荐

  1. MathType7安装使用及please restart word to load mathtype addin properly的问题

    MathType7安装使用及please restart word to load mathtype addin properly的问题.最近在自己的电脑上安装Mathtype7,把遇到的问题和解决办 ...

  2. vue项目经常遇到的Error: Loading chunk * failed

    vue项目随着代码量.业务组件.路由页面等的丰富,出于性能要求考虑不得不使用代码分割技术实现路由和组件的懒加载,这看似没什么问题 当每次通过npm run build构建生产包并部署到服务器后,操作页 ...

  3. .NET C#基础(6):命名空间 - 有名字的作用域

    0. 文章目的   面向C#新学者,介绍命名空间(namespace)的概念以及C#中的命名空间的相关内容. 1. 阅读基础   理解C与C#语言的基础语法.   理解作用域概念. 2. 名称冲突与命 ...

  4. MySQL 8.0 新特性梳理汇总

    一 历史版本发布回顾 从上图可以看出,基本遵循 5+3+3 模式 5---GA发布后,5年 就停止通用常规的更新了(功能不再更新了): 3---企业版的,+3年功能不再更新了: 3 ---完全停止更新 ...

  5. 编程技巧│提高 Javascript 代码效率的技巧

    目录 一.变量声明 二.三元运算符 三.解构赋值 四.解构交换 五.箭头函数 六.字符串模版 七.多值匹配 八.ES6对象简写 九.字符串转数字 十.次方相乘 十一.数组合并 十二.查找数组最大值最小 ...

  6. python小题目练习(13)

    题目:封装用户的上网行为 实现代码: """Author:mllContent:封装用户的上网行为Date:2020-01-19"""def ...

  7. gslb(global server load balance)技术的一点理解

    gslb(global server load balance)技术的一点理解 前言 对于比较大的互联网公司来说,用户可能遍及海内外,此时,为了提升用户体验,公司一般会在离用户较近的地方建立机房,来服 ...

  8. 『现学现忘』Git后悔药 — 29、版本回退git reset --mixed命令说明

    git reset --mixed commit-id命令:回退到指定版本.(mixed:混合的,即:中等回退.) 该命令不仅修改了分支中HEAD指针的位置,还将暂存区中数据也回退到了指定版本. 但是 ...

  9. 史上最全学习率调整策略lr_scheduler

    学习率是深度学习训练中至关重要的参数,很多时候一个合适的学习率才能发挥出模型的较大潜力.所以学习率调整策略同样至关重要,这篇博客介绍一下Pytorch中常见的学习率调整方法. import torch ...

  10. UI自动化测试执行问题总结

    ------------恢复内容开始------------ ![image](https://img2022.cnblogs.com/blog/1510476/202206/1510476-2022 ...