3965: 序列(seq)

本文探讨了如何构造一个特定长度的排列,使其同时满足最长上升子序列和最长下降子序列的预设长度条件。通过分析不同子任务,提出了解决方案,并提供了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时间限制: 1 Sec 内存限制: 512 MB Special Judge
提交: 52 解决: 23
[提交][状态][博客][加入收藏]
题目描述
给定 N,A,BN,A,B,构造一个长度为 NN 的排列,使得:
排列长度为 N;
最长上升子序列长度为 A;
最长下降子序列长度为 B。
我们有 SPJ,有解任意给出一组,否则说明无解。
输入
第一行一个整数 TT (1≤T≤101≤T≤10), 表示数据组数.
接下来 T 行,每行三个正整数 N、A、B。

输出
对每组数据:
如果有解,输出两行,第一行一个字符串 Yes,接下来一行 N 个整数,表示排列。
否则, 输出一行一个字符串 No。
样例输入
3
4 2 2
4 4 1
4 3 3
样例输出
Yes
3 4 1 2
Yes
1 2 3 4
No
提示
数据范围和子任务
对于全部的测试数据,保证 T≤10,N≤105,∑N≤2×105T≤10,N≤105,∑N≤2×105
子任务 1(20 分):N≤5N≤5 .
子任务 2(30 分):每组数据均满足 N=A×BN=A×B .
子任务 3(20 分):B≤2B≤2 .
子任务 4(30 分):无特殊限制

来源
hnsdfz国庆集训day2

题解:
对子任务2,由N=AB容易想到将N分为B段长度为A的连续串,要使最长下降子序列长度为B,可以在每段中取一个;使最长上升子序列长度为A,可以在每一段中都递增。那么就要使一段段之间递减(否则就会小于B),且每一段单独递增(否则就会大于B且小于A)。
由子任务2推广到全部数据:同样将N分为B段,且最长一段长度为N,一段段之间递减,单独每一段递增即可。那么考虑不可行的极端情况:1.A+B-1>N,即使除了最长段外每一段长度都为1,也无法生成B段;2.A
B<N,即使每段长度都为A,也无法填满。又因为在这种情况下,其他方法也无法填满,故此解为最优。

代码

#include<bits/stdc++.h>
using namespace std;
int R(){
	int s=0; char c=getchar(); while(c<'0' || c>'9') c=getchar();
	while(c>='0' && c<='9') s=s*10+c-'0',c=getchar(); return s;
}
const int N=1e5+10;
int T,ans[N];
int main()
{
	cin>>T;
	while(T--){
		int n=R(),a=R(),b=R(); 
		if(a+b-1>n || a*b<n) {cout<<"No"<<endl; continue;}
		int x,y; 
		if(a==1) x=0,y=0;
		else x=(n-b)/(a-1),y=(n-b)%(a-1)+1;
		int t=n+1; 
		for(int i=1;i<=x;i++){
			for(int j=a;j>=1;j--) ans[(i-1)*a+j]=--t;
		}
		for(int i=x*a+y;i>=x*a+1;i--) ans[i]=--t;
		for(int i=x*a+y+1;i<=n;i++) ans[i]=--t;
		cout<<"Yes"<<endl;
		for(int i=1;i<n;i++) printf("%d ",ans[i]); printf("%d\n",ans[n]); 
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值