2021 ICPC 江西省大学生程序设计竞赛 Character Distance

Character Distance(思维、模拟)4星

题意:

给你一个有 n n n个元素的序列,要求选择其中任意至少一个数,使对于这个数在序列中的位置间隔恰好为 m ( 1 ≤ i < j , a i = a j = x , m ≤ j − i ) m(1\leq i< j,a_i=a_j=x,m\leq j-i) m(1i<j,ai=aj=x,mji)且要求序列满足字典序最小,若无法满足输出-1

1 ≤ n , m ≤ 1 0 6 1\leq n,m\leq 10^6 1n,m106

题解:

只需要找到一个数让他满足上述条件即可

  • 当有元素的出现次数为1时,直接输出 s o r t sort sort后的序列即可

  • 其他情况

    p o s pos pos为元素的首位置(排序后), c n t cnt cnt为个数

    • 对于一个元素x,若满足 p o s + ( c n t − 1 ) ∗ m < = m pos+(cnt-1)*m<=m pos+(cnt1)m<=m,则当尽可能选择后面的元素使可以使字典序尽可能小
    • 对于其他情况—— p o s + ( c n t − 1 ) ∗ m > n & & 1 + ( c n t − 1 ) ∗ m ≤ n pos+(cnt-1)*m>n\&\& 1+(cnt-1)*m\leq n pos+(cnt1)m>n&&1+(cnt1)mn时,当第一个 x x x的位置越靠后时字典序越小
    • x x x都不满足上述情况则为输出-1
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
int n,m;
int g[N];
int ans1[N],ans2[N];
map<int,int>mp;
bool check(int ans1[],int ans2[]){
    for(int i=1;i<=n;i++){
        if(ans1[i]>ans2[i]) return false;
        else if(ans1[i]<ans2[i]) return true;
    }
    return true;
}
void solve(){
    cin>>n>>m;
    mp.clear();
    for(int i=1;i<=n;i++){
        cin>>g[i];
        ans1[i]=ans2[i]=0;
        if(!mp.count(g[i])) mp[g[i]]=1;
        else mp[g[i]]++;
    }
    int mi=N;
    sort(g+1,g+1+n);
    for(auto [x,y]:mp){
        if(y==1){
            for(int i=1;i<=n;i++) cout<<g[i]<<' ';
            cout<<endl;
            return ;
        }
    }
    int f1=0,pos1=-1;//第一种情况,从pos往后插
    for(int i=n;i>=1;i--){
        int j=i-1;
        while(g[j]==g[i]&&j>=1) j--;
        i=j+1;
        if(i+(mp[g[i]]-1)*m<=n){
            pos1=g[i],f1=1;
            int cnt=mp[g[i]],t=i;
            while(cnt--){
                ans1[t]=g[i];
                t+=m;
            }
            break;
        }
    }
    if(f1){
        for(int i=1,j=1;i<=n;i++){
            if(g[i]==pos1) continue;
            while(ans1[j]&&j<=n) j++;
            ans1[j++]=g[i];
        }
    }
    int pos2=0,f2=0,cnt=N;//第二种情况,从n往前插
    for(int i=1;i<=n;i++){
        if(i+(mp[g[i]]-1)*m>n&&1+(mp[g[i]]-1)*m<=n){
            if(!f2){
                f2=1;
                cnt=mp[g[i]];
                pos2=g[i];
            }
            else{
                if(cnt>mp[g[i]]){
                    cnt=mp[g[i]];
                    pos2=g[i];
                }
                else if(cnt==mp[g[i]]) pos2=min(pos2,g[i]);
            }
        }
        int j=i+1;
        while(g[i]==g[j]&&j<=n) j++;
        i=j-1;
    }
    if(f2){
        int t=n;
        while(cnt--){
            ans2[t]=pos2;
            t-=m;
        }
        for(int i=1,j=1;i<=n;i++){
            if(g[i]==pos2) continue;
            while(ans2[j]&&j<=n) j++;
            ans2[j++]=g[i];
        }
    }
    if(f1&&!f2){
        for(int i=1;i<=n;i++) cout<<ans1[i]<<' ';
    }
    else if(!f1&&f2){
        for(int i=1;i<=n;i++) cout<<ans2[i]<<' ';
    }
    else if(f1&&f2){
        if(check(ans1,ans2)){
            for(int i=1;i<=n;i++) cout<<ans1[i]<<' ';
        }
        else{
            for(int i=1;i<=n;i++) cout<<ans2[i]<<' ';
        }
    }
    else cout<<-1;
    cout<<endl;
}
signed main(){
    //freopen("in.txt","r",stdin);
	//freopen("ans.txt","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值