• “蔚来杯“2022牛客暑期多校训练营9 E题: Longest Increasing Subsequence


    E题: Longest Increasing Subsequence

    原题链接:https://ac.nowcoder.com/acm/contest/33194/E

    题目大意

    给定整数 m ( 1 ≤ m ≤ 1 0 9 ) m(1\le m\le 10^9) m(1m109) ,构造一个长度不超过 100 100 100 的排列 p p p ,使得 p p p 中恰好有 m m m 个最长递增子序列。

    如果存在,则输出任意方案即可。否则输出"-1"。

    题解

    m m m 进行二进制拆分。
    m m m 的最高位为 2 M 2^M 2M ,则预构造一个序列如下:
    2 , 1 , 4 , 3 , . . . , 2 × M , 2 × M − 1 2,1,4,3,...,2\times M,2\times M-1 2,1,4,3,...,2×M,2×M1

    这个序列有 2 M 2^M 2M 个长为 M M M L I S LIS LIS
    然后考虑 m m m 的剩下位。若 m m m 包含 2 k 2^k 2k ,则在 2 × k − 1 2\times k-1 2×k1 (第 2 k 2k 2k 个位置)后插入 M − k M-k Mk 个未出现的递增的数字,恰好增加 2 k 2^k 2k 个长为 M M M L I S LIS LIS
    从大到小枚举 k k k 进行插入,可以构造得到一个排列恰好有 m m m L I S LIS LIS

    参考下例 m = 27 = [ 11011 ] 2 m=27=[11011]_2 m=27=[11011]2
    预构造: 2 , 1 , 4 , 3 , 6 , 5 , 8 , 7 2,1,4,3,6,5,8,7 2,1,4,3,6,5,8,7
    处理 2 3 2^3 23 后: 2 , 1 , 4 , 3 , 6 , 5 , 2,1,4,3,6,5, 2,1,4,3,6,5,9 , 8 , 7 ,8,7 ,8,7
    处理 2 1 2^1 21 后: 2 , 1 , 2,1, 2,1,10,11,12 , 4 , 3 , 6 , 5 , 9 , 8 , 7 ,4,3,6,5,9,8,7 ,4,3,6,5,9,8,7
    处理 2 0 2^0 20 后:13,14,15,16 , 2 , 1 , 10 , 11 , 12 , 4 , 3 , 6 , 5 , 9 , 8 , 7 ,2,1,10,11,12,4,3,6,5,9,8,7 ,2,1,10,11,12,4,3,6,5,9,8,7

    但是这种策略构造得到的排列长度最坏为 ⌊ l o g 2 n ⌋ \lfloor log^2n\rfloor log2n ,不一定合法。
    不难发现,在越前面的位置插入的数字越多,不妨共用后面的数字,则插入最多 ⌊ l o g n ⌋ \lfloor logn\rfloor logn 个数字,总长度最坏为 ⌊ 3 l o g n ⌋ < 100 \lfloor 3logn\rfloor<100 3logn<100

    仍以 m = 27 = [ 11011 ] 2 m=27=[11011]_2 m=27=[11011]2 为例。
    预构造: 2 , 1 , 4 , 3 , 6 , 5 , 8 , 7 2,1,4,3,6,5,8,7 2,1,4,3,6,5,8,7
    最终结果:9 , 2 , 1 , ,2,1, ,2,1,10,11 , 4 , 3 , 6 , 5 , ,4,3,6,5, ,4,3,6,5,12 , 8 , 7 ,8,7 ,8,7

    不存在无解的情况。
    实际插入时可以用 s t d : : v e c t o r std::vector std::vector i n s e r t insert insert 操作,单次复杂度 O ( n ) O(n) O(n) ,但是在本题够用而且很方便。

    参考代码

    #include
    using namespace std;
    
    template<class T>inline void read(T&x){
    	char c,last=' ';
    	while(!isdigit(c=getchar()))last=c;
    	x=c^48;
    	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+(c^48);
    	if(last=='-')x=-x;
    }
    
    const int MAXN=1e2+5;
    int m;
    int n;
    int a[MAXN];
    
    int main()
    {
    	int T;read(T);
    	while(T--){
    		read(m);
    		if(m==1){
    			puts("1\n1");
    			continue;
    		}
    		int M=0;
    		while(1<<M<=m)++M;
    		--M;
    		vector<int>v;
    		for(int i=1;i<=M;++i){
    			v.push_back(2*i);
    			v.push_back(2*i-1);
    		}
    		for(int i=M-1,cnt=0;i>=0;--i){
    			if(m>>i&1){
    				while(cnt<M-i)v.insert(v.begin()+2*i,0),++cnt;//先标记插入位
    			}
    		}
    		for(int i=0,c=2*M;i<(int)v.size();++i){
    			if(v[i]==0)v[i]=++c;//从前往后递增赋值
    		}
    		cout<<(int)v.size()<<'\n';
    		for(int i=0;i<(int)v.size();++i)cout<<v[i]<<" \n"[i+1==(int)v.size()];
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
  • 相关阅读:
    网络爬虫-----http和https的请求与响应原理
    【Unity入门计划】Unity实例-C#如何通过封装实现对数据成员的保护
    城中村智能水电表改造,提升居民生活品质
    艾伦脑科学研究所,脑图谱,小鼠不同的功能脑区,可视化展示
    微软官方操作系统(需空U盘)
    Day34-Linux网络管理4
    Linux安装Oracle数据库
    【解决】VSCode编写C++自定义头文件undefined reference异常问题
    stm32f4xx-USART串口
    钡铼profinet总线模块可以拓展IO
  • 原文地址:https://blog.csdn.net/Spy_Savior/article/details/126369508