本文已参与「新人创作礼」活动,一起开启掘金创作之路。
@TOC
Codeforces Round #713 (Div. 3)-E. Permutation by Sum
传送门 Time Limit: 2 seconds Memory Limit: 256 megabytes
Problem Description
A permutation is a sequence of integers from to , in which all the numbers occur exactly once. For example, , , are permutations, and , , are not.
Polycarp was given four integers , , ( and () and asked to find a permutation of numbers from to that satisfies the following condition:
For example, for , , , and , the following permutations are suitable (not all options are listed):
Help Polycarp, for the given , , , and , find a permutation of numbers from to that fits the condition above. If there are several suitable permutations, print any of them.
Input
The first line contains a single integer (). Then test cases follow.
Each test case consist of one line with four integers (), (), (), ().
It is guaranteed that the sum of for all input data sets does not exceed .
Output
For each test case, output on a separate line:
If there are several suitable permutations, print any of them.
Sample Input
5
5 2 3 5
5 3 4 1
3 1 2 4
2 2 2 2
2 1 1 3
Sample Onput
1 2 3 4 5
-1
1 3 2
1 2
-1
题目大意
给你个数,让你找到一个的全排列,它满足从第个数累加到第个数的和等于。
解题思路
的全排列中,最大的数是,最小的数是,且各个数各不相同。 所以到这个数(记为)中,和的最小值是,和的最大值是。 如果界于这两个数之间,就能找到符合条件的全排列,否则就不行。 如果可以找到,就把到中的数先初始值为最小的到,再不断将这些数变大(变得尽量大),知道他们的和等于。 变大过程是从最后一个数()开始变到尽可能大(不超过且和不超过),然后倒数第二个数()开始变到尽可能大(不超过且和不超过)知道和等于。
AC代码
#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int a[505];
int getNext(map<int,bool>::iterator &it)//找到下一个输出的数(可以先看下面主函数)
{
while(it->second==false)it++;//这个数出现过了,继续往下找
return it->first;//找到返回
}
int main()
{
int N;
cin>>N;
while(N--)//N组测试样例
{
int n,l,r,s;
cin>>n>>l>>r>>s;
int num=r-l+1;//从l到r共有r-l+1个数
int m=(1+num)*num/2;//和最小为m
int M=(n-num+1+n)*num/2;//和最大为M
if(s<m||s>M)//如果s不介于他们之间
{
puts("-1");//不行
continue;
}
for(int i=0;i<num;i++)//l到r初始值从1到num
{
a[i]=i+1;
}
int diff=s-m;//s比现在的这num个数大diff,还需要再加上diff
int toM=n;//一个数最大变到n
int loc=num-1;//目前处理的数的下标(从第r个数开始处理)
while(diff)//差值不为0
{
int thisMaxDiff=toM-a[loc];//这个数改变所能引起的最大的差值
int thisRealDiff=min(thisMaxDiff, diff);//真正变大的量(不能超过diff)
diff-=thisRealDiff;//差距减小了thisRealDiff
a[loc]+=thisRealDiff;//这个数变大了thisRealDiff
toM=a[loc]-1;//一个数最大变到的数-1
loc--;//下次处理前面一个数
}
map<int,bool>ma;//map储存一个数是否还能使用
for(int i=1;i<=n;i++)
{
ma[i]=1;//初始值还可以使用
}
for(int i=0;i<num;i++)
{
ma[a[i]]=0;//从l到r中要出现的数不能再使用
}
map<int,bool>::iterator it=ma.begin();//从头开始找
// for(map<int,bool>::iterator temp=ma.begin();temp!=ma.end();temp++)
// {
// printf("%d %d\n",temp->first, temp->second);
// }
loc=0;
for(int i=1;i<=n;i++)
{
if(i>=l&&i<=r)//是l到r中的一个数
{
printf("%d ",a[loc++]);//以及计算出,直接输出
}
else//否则
{
printf("%d ",getNext(it));//没出现过的数中找到下一个
it++;
}
}
puts("");//换行
}
return 0;
}
同步发文于我的CSDN,原创不易,转载请附上原文链接哦~
Tisfy:letmefly.blog.csdn.net/article/det…