AtCoder Grand Contest 012 C

感觉APIO2022的最后一题就是从这题改来的,简化了一些后又加上了一些奇怪的优化。

首先我们将这题转成和APIO2022一样的格式——如果我们将最终答案分为两个部分,前半部分有n个上升子序列,并且值域在1m,后半部分是1,2,3,...,m的序列。不难发现这个构造出的序列一定有n个符合题目要求的子序列。

比如n=7时,有:

1 2 3 1 2 3

那么前半部分有1,2,3,12,13,23,1237个上升子序列,后半部分也有唯一对应的相等串,比如2323

再比如n=13时,有

3 2 4 1 5 1 2 3 4 5

前半部分有3,2,4,1,5,24,34,25,35,45,15,245,34513个上升子序列,后半部分也有对应的相等串,比如345345

至此,我们就将题面转化为:

构造一个长度不超过100(因为后面我们还要重复一遍)的数列,使得上升子序列个数为n

这里我们暂且认为空子序列也是上升的,也就是我们要求出有(n+1)个上升子序列的数列。

那么不难发现,如果我们当前有一个数列A,如果我们加入minA1,则上升子序列个数+1;加入maxA+1,则上升子序列个数×2

故我们可以将(n+1)二进制分解,从而得到每一处位置是加入一个最小值还是最大值,从而求出整个数列。

这样,我们使用的数不超过logn,数列的长度不超过2logn,可以AC。

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

using ll=long long;
ll n,id,num,a[205];
std::vector<ll> tp,smallest,biggest;

int main() {
	scanf("%lld",&n); n++;
	ll dig=0,temp=1; while(temp<=n) dig++,temp<<=1ll; dig--;
	for(int i=1;i<=dig;i++) tp.push_back(0);
	ll p=(ll)tp.size(),d=0;
	while(p>0) {
		if(n&(1ll<<d)) tp.insert(tp.begin()+p,1);
		p--; d++;
	}
	for(auto item : tp) {
		if(item) smallest.push_back(++id);
		else biggest.push_back(++id);
	}
	for(int i=(int)smallest.size()-1;~i;i--) a[smallest[i]]=++num;
	for(int i=0;i<(int)biggest.size();i++) a[biggest[i]]=++num;
	for(int i=1;i<=num;i++) a[++id]=i;
	printf("%d\n",id); for(int i=1;i<=id;i++) printf("%d ",a[i]);
	return 0;
}
posted @   Nastia  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示