2021江西省赛 D.Character Distance(思维,构造)

本文详细介绍了如何在已排序的序列中插入元素,使得相邻元素之间保持指定的间距,并确保序列仍有序。首先,特判所有元素各不相同的情况,直接按序输出。接着,通过排序找到可以满足条件的位置插入元素,同时计算无法满足条件时倒序放置的最优解。最后,暴力比较两种方案的字典序,输出最优解。涉及的算法包括排序、贪心策略以及字符串处理技巧。
摘要由CSDN通过智能技术生成
题意:

在这里插入图片描述

解法:
设cnt[i]为数字i出现的次数,
如果存在cnt[i]=1,那么按序输出即可,这个地方特判一下.

先对序列排序.

对于数字x,两种情况
1.<x的放完然后间隔d距离放x,最后将x以外的数按序插空即可.
2.如果情况1无法实现(剩下的距离不够放x),
那么考虑x从最后开始倒序放(可以推出倒序最优),
设r[x]表示将x倒序放之后,左边还剩下多少空位.

对于满足情况1的x,显然选择的x越大越好,取出最优的x,记为pos1,
对于不满足情况1,只满足情况2的x:(如果满足情况1肯定比情况2,所以这里只考虑不满足情况1)
空位越多越好,如果空位相同的数字越小越好,取出最优的x,记为pos2.

用pos1和pos2构造出两个答案,暴力比较字典序取最优解即可.
code:
#include<bits/stdc++.h>
// #define SYNC_OFF
#define int long long
#define ll long long
#define ull unsigned long long
//fast-coding
#define ST(x) x.begin()
#define ED(x) x.end()
#define RST(x) x.rbegin()
#define RED(x) x.end()
#define CL(x) x.clear();
#define all(a,n) a+1,a+1+n
#define ff(i,n) for(ll i=1;i<=n;i++)
#define rff(i,n) for(ll i=n;i>=1;i--)
#define fff(i,n) for(ll i=0;i<n;i++)
#define rfff(i,n) for(ll i=n-1;i>=0;i--)
#define SC(x) scanf("%s",x)
#define SL(x) strlen(x)
#define pss(a) push_back(a)
#define ps(a) push(a)
#define SZ(x) (int)x.size()
#define pee puts("");
#define eee putchar(' ');
#define re readdd()
#define pr(a) printtt(a)
int readdd(){int x=0,f=1;char c=getchar();//
while(!isdigit(c)&&c!='-')c=getchar();
if(c=='-')f=-1,c=getchar();
while(isdigit(c))x=x*10+c-'0',c=getchar();
return f*x;}
void printtt(int x){if(x<0)putchar('-'),x=-x;//
if(x>=10)printtt(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}//
int ppow(int a,int b,int mod){a%=mod;//
int ans=1%mod;while(b){if(b&1)ans=(long long)ans*a%mod;
a=(long long)a*a%mod;b>>=1;}return ans;}
bool addd(int a,int b){return a>b;}
int lowbit(int x){return x&-x;}
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
bool isdigit(char c){return c>='0'&&c<='9';}
bool Isprime(int x){
    for(int i=2;i*i<=x;i++)if(x%i==0)return 0;
    return 1;
}
void ac(int x){if(x)puts("YES");else puts("NO");}
//short_type 
#define VE vector<int>
#define PI pair<int,int>
//
using namespace std;
// const int mod=998244353;
const int mod=1e9+7;
const int maxm=2e6+5;
int a[maxm];
int cnt[maxm];
int ok[maxm];
int r[maxm];
int ans[2][maxm];
int n,d;
int check(){//比较字典序
    ff(i,n){
        if(ans[0][i]==ans[1][i])continue;
        if(ans[0][i]<ans[1][i])return 0;
        else return 1;
    }
    return 0;
}
void solve(){
    n=re,d=re;
    ff(i,n)a[i]=re;
    sort(a+1,a+1+n);
    //init
    ff(i,n)ok[i]=0;
    ff(i,n)ans[0][i]=ans[1][i]=0;
    ff(i,n)cnt[i]=0;
    ff(i,n)r[i]=-1;
    //
    ff(i,n)cnt[a[i]]++;
    ff(i,n){
        if(a[i]!=a[i-1]){//枚举x
            int c=cnt[a[i]];
            int len=1+(c-1)*d;
            if((i-1)+len<=n){//<x的放完然后放x,是否可以放下
                ok[a[i]]=1;
            }
            if(len<=n){//倒着放x,前面能有多少个空位
                r[a[i]]=n-len;
            }
        }
    }
    int one=0;
    ff(i,n){
        if(cnt[i]==1)one=1;
    }
    if(one){
        ff(i,n){
            pr(a[i]);eee;
        }
        pee;return ;
    }
    //计算答案
    int pos1=-1,pos2=-1;
    //ok[]的取越后面的越优,因此取最后一个
    ff(x,n){
        if(!cnt[x])continue;
        if(ok[x]){
            pos1=x;       
        }
    }
    //r[]取空位最多的,如果空位相同取数字小的
    ff(x,n){
        if(!cnt[x])continue;
        if(ok[x])continue;//ok的话不考虑pos2,pos1肯定更优
        if(r[x]!=-1){
            //取空位最大的,空位相同取数字小的
            if(pos2==-1){
                pos2=x;
            }else if(r[pos2]<r[x]){
                pos2=x;
            }else if(r[pos2]==r[x]){
                pos2=min(pos2,x);
            }
        }
    }
    // cout<<pos1<<' '<<pos2<<endl;
    //
    if(pos1!=-1){
        int fp=0;
        ff(i,n){
            if(a[i]==pos1){
                fp=i;break;
            }
        }
        for(int i=1,p=fp;i<=cnt[pos1];i++,p+=d){
            ans[0][p]=pos1;
        }
        for(int i=1,c=1;i<=n;i++){
            while(ans[0][c])c++;
            if(a[i]==pos1)continue;
            ans[0][c++]=a[i];
        }
    }
    if(pos2!=-1){
        for(int i=1,p=n;i<=cnt[pos2];i++,p-=d){
            ans[1][p]=pos2;
        }
        for(int i=1,c=1;i<=n;i++){
            while(ans[1][c])c++;
            if(a[i]==pos2)continue;
            ans[1][c++]=a[i];
        }
    }
    // cout<<pos1<<' '<<pos2<<endl;
    int p=-1;
    if(pos1!=-1&&pos2!=-1){
        p=check();
    }else if(pos1!=-1){
        p=0;
    }else if(pos2!=-1){
        p=1;
    }else{
        puts("-1");return ;
    }
    ff(i,n){
        pr(ans[p][i]);eee;
    }
    pee;
}
void Main(){
    #define MULTI_CASE
    #ifdef MULTI_CASE
    int T;cin>>T;while(T--)
    #endif
    solve();
}
void Init(){
    #ifdef SYNC_OFF
    ios::sync_with_stdio(0);cin.tie(0);
    #endif
    #ifndef ONLINE_JUDGE
    freopen("../in.txt","r",stdin);
    freopen("../out.txt","w",stdout);
    #endif
}
signed main(){
    Init();
    Main();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值