cf 1512 E. Permutation by Sum
题意:
我们定义排列的概念为:从1到n的整数组成的序列,每个数字只出现一次
现在给你n,l,r,s,让你构造一个长度为n的排列,使得其中的第l到第r项和为s
输出任意答案
题解:
又是构造题,构造题考察经验思维
我们想想区间[l,r]的和为s
区间长度为len = r - l+1
区间长度为len的能组成的最小和min就是1+…+len
最大和就是n+n-1…n-lenn+1
如果s不在这个范围内,说明s无法构造,输出-1
如果s可以构造说明最小和+?就是s
这个?怎么求
ave = (s-min)/len:区间内每个数比最小值平均大Ave
那么我们这个区间至少应该是i+ave(1<=i<=len)
这样构造的区间一定小于等于s(我们去差为cha),且区间为从小到大顺序排列
如果小于s(cha>0),我们就让最后一位+1,cha–,如果cha还大于0,我们就让倒数第二位+1,cha–,从后往前一次增加
为什么这样?
为什么要+1呢?因为每位这个区间是最接近s的连续区间,所以从这个开始枚举所需要的可能性最少
为什么要倒着循环+1呢?因为这个循环肯定是不可能全部进行完的(因为我们已经求的原本的区间是最接近s的),所以在某个时刻cha会等于0,循环中断,如果我们正着循环,在第i个数加完后中断,第i个数就等于第i+1个数(因为原本序列是顺序排列的,而i加了1,第i+1位没变),会出现重复数,但是如果倒着循环就不会存在,因为后一位始终大于前一位
详细看代码
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <map>
#include <set>
#define G 10.0
#define LNF 1e18
#define eps 1e-6
#define ll long long
#define INF 0x7FFFFFFF
#define PI acos(-1.0)
#define pb(x) push_back(x)
#define SP system("pause")
#define mm(a, b) memset(a, b, sizeof(a))
#define fir(i, a, n) for (ll i = a; i <= n; i++)
#define rif(i, a, n) for (ll i = a; i >= n; i--)
#define each_cass(cass) for (cin >> cass; cass; cass--)using namespace std;
void solve()
{ll n, l, r, s;cin >> n >> l >> r >> s;ll Min = (1 + r - l + 1) * (r - l + 1) / 2;ll Max = (n + n - r + l) * (r - l + 1) / 2;if (s > Max || s < Min){cout << "-1" << endl;return;}int cha = s - Min;vector<int> zhong;vector<int> qian;vector<int> hou;int pingduo = cha / (r - l + 1);//代表[1~(r-l+r)]每个数至少要加的数int len = r - l + 1;for (int i = 1; i <= len; i++)zhong.push_back(i+pingduo),cha-=pingduo;if (cha)//如果cha不为0,就最大的几个数+1直到cha=0{for (int i = zhong.size() - 1; cha && i >= 0; i--){zhong[i]++;cha--;}}int vis[10000] = {0};//记录,防止重复for (int i = 0; i < zhong.size(); i++)vis[zhong[i]] = 1;for (int i = 1; i <= n; i++){if (qian.size() == l - 1)//前面的数是(l-1)个break;if (!vis[i])qian.push_back(i), vis[i] = 1;}for (int i = 1; i <= n; i++){if (hou.size() == n - r)//后面的数是(n-r)个break;if (!vis[i])hou.push_back(i), vis[i] = 1;}//输出for (int i = 0; i < qian.size(); i++)cout << qian[i] << " ";for (int i = 0; i < zhong.size(); i++)cout << zhong[i] << " ";for (int i = 0; i < hou.size(); i++)cout << hou[i] << " ";cout << endl;
}
int main()
{int cass;each_cass(cass){solve();}return 0;
}