HDU 6852 Increasing and Decreasing 构造
题意:
给你一个n,x,y。你需要找出来一个长度为n的序列,使得这个序列满足最长上升子序列长度为x,最长下降子序列长度为y。且这个序列中每个数字只能出现一次
且要保证最后输出的序列的字典序最小
题解:
因为要保证字典序最小,那么肯定是使用前n个数,即[1,n]
我们可以首先让下降子序列用最大的值,且把它们放在序列最后,例如n=10,x=5,y=5
那么我们就让下降子序列使用6,7,8,9,10.而且把这5个数反转一下变成10,9,8,7,6追加到序列尾部
那么剩下的n-y个数去构建出来一个最长上升子序列为x-1的序列就行
为什么是x-1?因为最后y个数比前的任意一个数都要大,所以最长上升子序列部分这里也要占用1个位置
然后我们挑选出来x-1个数组成上升序列,挑选出来的数用wi表示(还是用的上面10,5,5的例子)
1 w1 2 w2 3 w3 4 w4
这个序列的1,2,3,4这些位置可以用长度为y-1的下降序列来插入其中
因为题目要求输出字典序最小,那么我们就把w4尽可能使用y-1个数,然后w3尽可能使用y-1个数,依次类推
假设w1部分使用了h个数,那么1 w1这1+h个位置使用前h+1个数来构造序列
这样构造就是最小的
题目要特判x*y>=n&&x+y<=n+1输出NO,我的x+y<=n+1是找出来的,但是x*y>=n这个我也不清楚。。。。
代码:
#include<stack> #include<queue> #include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define fi first #define se second using namespace std; typedef long long ll; const int maxn=1e5+10; const int mod=1e9+7; typedef long long ll; ll n,x,y,ans[maxn]; ll pre[maxn],len[maxn]; int main() { ll t; scanf("%lld",&t); while(t--) { scanf("%lld%lld%lld",&n,&x,&y); if(1ll*x*y>=n&&x+y<=n+1) { printf("YES\n"); ll res=n-y; for(ll i=1; i<=x-1; i++) //枚举这是第几个空隙 { len[i]=res-1ll*(x-1-i)*y; //应该向第i个空隙内插入多少数 if(len[i]<=0) //x-1-i表示这个空隙之前有多少个空隙 { //至于为什么要乘于y,是因为下降序列y-1个数,上升序列的一部分占1个位置 len[i]=1; } res=res-len[i]; pre[i]=pre[i-1]+len[i]; } for(ll i=1; i<=x-1; i++) { for(ll j=pre[i-1]+1; j<=pre[i]; j++) { ans[i]=pre[i]-j+pre[i-1]+1; //这个就相当于用【1,n】这n个数,来构造长度为n的序列 printf("%lld ",ans[i]); } } for(ll i=n; i>=n-y+1; i--) { printf("%lld%c",i,i==n-y+1?'\n':' '); } } else { printf("NO\n"); } } return 0; }