Codeforces Round #713(Div. 3)
E.Permutation by Sum
题意:给定整数n,l, r, s,要求你找一个长度为n的排列p使得 s = p l + p l + 1 + . . . + p r s=p_l+p_{l+1}+...+p_r s=pl+pl+1+...+pr, 若有多个则输出任意一个,若无解则输出-1
思路:对于所给区间[l,r],我们先特判 s m i n = 1 + 2 + . . . + p r − l + 1 s_{min}=1+2+...+p_{r-l+1} smin=1+2+...+pr−l+1和 s m a x = p n + p n − 1 + . . . + p n − r + l s_{max}=p_n+p_{n-1}+...+p_{n-r+l} smax=pn+pn−1+...+pn−r+l的值与s的关系,若 s m i n < = s < = s m a x s_{min}<=s<=s_{max} smin<=s<=smax ,则先将区间[l,r]中的数依次赋为 s m i n s_{min} smin中的值,否则无论我们怎么调整区间[l,r]的数都是无解,
接下来我们按照一种类似于“进制”的思想,优先调整后端的数,若后端的数已达到最大,再调整前端的数,依次迭代,这样我们就处理好了区间[l,r]中的数,并对于这些数打上标记,最后对于整个排列,我们再将没有标记过的数依次塞入就行
Code:
#include<bits/stdc++.h>
#define int long long
#define rep(i,a,n) for(int i = a; i<=n; i++)
#define pb push_back
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int mxn=510;
int p[mxn], vis[mxn];
auto solve()->void{
int n, l, r, s;
cin>>n>>l>>r>>s;
rep(i,1,n) vis[i]=0, p[i]=0;
int mi=0, ma=0;
rep(i,1,r-l+1) mi+=i;
for(int i=n; i>=n-(r-l+1)+1; i--) ma+=i;
if(s>ma||s<mi) {cout<<-1<<'\n';return;}
s-=mi;//需要调整的差值
rep(i,l,r) p[i]=i-l+1;
for(int i=r; i>=l; i--){
if(s>=n-(r-l+1)){
s-=n-(r-l+1);
p[i]+=n-(r-l+1);
vis[p[i]]=1;
}
else{
p[i]+=s;
vis[p[i]]=1;
s=0;
}
}
rep(i,1,n){
if(p[i]==0){
rep(j,1,n){
if(!vis[j]){
p[i]=j;
vis[j]=1;
break;
}
}
}
}
rep(i,1,n) cout<<p[i]<<" \n"[i==n];
}
signed main(){
ios;
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}