Codeforces Round #713(Div. 3) - E. Permutation by Sum

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+...+prl+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+pn1+...+pnr+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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值