P8976「DTOI-4」排列 题解

一、题意

构造一个长度为 n n n 的序列 P P P , 使 P P P 的前半段的数之和 ≥ a \geq a a , 后半段的数之和 ≥ b \geq b b

二、分析

1 ∼ n \sim n n 每个数只能用一次,所以整个序列之和是 $\dfrac{n(n + 1)}{2} $(为方便,以下统称 S 1 S1 S1 ) 半个序列之和最大是 n 2 ( n 2 + 1 + n ) 2 \dfrac{\dfrac{n}{2}\left(\dfrac{n}{2} + 1 + n\right)}{2} 22n(2n+1+n) (为方便,以下统称 S 2 S2 S2 ),如果 a + b > S 1 a + b > S1 a+b>S1 a > S 2 a > S2 a>S2 b > S 2 b > S2 b>S2 ,就说明无解。

构造时我们只看前半个序列 (为方便,以下统称 A A A )。

一开始,我们将 A A A 置为 1 ∼ n 2 1 \sim \dfrac{n}{2} 12n ,和为 n 2 ( n 2 + 1 ) 2 \dfrac{\dfrac{n}{2}\left(\dfrac{n}{2} + 1\right)}{2} 22n(2n+1) (为方便,以下统称 S 3 S3 S3 ),如果 S 3 ≥ a S3 \geq a S3a ,那么就输出 1 ∼ n 1 \sim n 1n

否则令 T = a − S 3 T = a - S3 T=aS3 ,$ X = T \div \dfrac{n}{2}$ ,$ F = T % \dfrac{n}{2}$ 。

下面来解释一下,若不够就得补上,每个数最多可以增大 n 2 \dfrac{n}{2} 2n ,我们可以将 A A A 的后 X X X 个数( n 2 \dfrac{n}{2} 2n n 2 − 1 \dfrac{n}{2} - 1 2n1 n 2 − 2 \dfrac{n}{2} - 2 2n2 … \dots )换成 P P P 的后 X X X 个数( n n n n − 1 n - 1 n1 n − 2 n - 2 n2 … \dots ),此时还会少 F F F ,我们可以将 A A A 的第 n 2 − X \dfrac{n}{2} - X 2nX 个数换成 P P P 的第 n 2 − X + F \dfrac{n}{2} - X + F 2nX+F 个数(这一步在 X ≠ 0 X \ne 0 X=0 的情况下才需要进行)

这样序列 A A A 就构造完成了,输出 A A A ,然后将没用过的数输出即可。

三、代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,a,b;
int main()
{
    cin>>t;
    while(t--)
    {
    	cin>>n>>a>>b;
    	if(n*(n+1)/2<a+b||n*(n+1)/2-(n/2)*(n/2+1)/2<a||n*(n+1)/2-(n/2)*(n/2+1)/2<b)//判断是否无解 
    	{
    		cout<<-1<<endl;
    		continue;
		}
		ll t=(n/2)*(n/2+1)/2;//相当于上面的T 
		if(t<a)
		{
			ll t1=(a-t)/(n/2),x=(a-t)-t1*(n/2);//相当于上面的X、F 
			for(ll i=1;i<=n/2-t1-(bool)(x);i++)cout<<i<<" ";
			if(x)cout<<x+n/2-t1<<" ";
			for(ll i=n-t1+1;i<=n;i++)cout<<i<<" ";
			//构造A 
			for(ll i=n/2-t1;i<=n-t1;i++)
			{
				if(i==x+n/2-t1)continue;
				cout<<i<<" ";
			}
			//将没用过的数输出
			cout<<endl;
		}
		else
		{
			for(ll i=0;i<n;i++)cout<<i+1<<" ";
			cout<<endl;
		}
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值