bzoj1562 noi2009变换序列

博客探讨了如何解决NOI2009中的一道题目,该题目涉及整数变换序列。给定N个整数及其变换后的距离,目标是找到满足条件的变换序列,使得所有整数在变换后仍覆盖所有可能值,并确保字典序最小。文章可能详细介绍了问题的解决策略和算法实现。
摘要由CSDN通过智能技术生成

http://www.elijahqi.win/archives/1141
题目描述

对于N个整数0,1,…,N-1,一个变换序列T可以将i变成Ti,其中:Ti∈{0,1,…,N-1}且 {Ti}={0,1,…,N-1}。 x,y∈{0,1,…,N-1},定义x和y之间的距离D(x,y)=min{|x-y|,N-|x-y|}。给定每个i和Ti之间的距离D(i,Ti),你需要求出一个满足要求的变换序列T。如果有多个满足条件的序列,输出其中字典序最小的一个。 说明:对于两个变换序列S和T,如果存在p

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 11000
using namespace std;
inline char gc(){
    static char now[1<<16], *S, *T;
    if(S==T){T=(S=now)+fread(now, 1, 1<<16, stdin); if(S==T)return EOF;}
    return *S++;
}
inline int read(){
    int x=0;char ch=gc();
    while (ch<'0'||ch>'9') ch=gc();
    while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();}
    return x;
}
struct node{
    int y,next;
}data[N<<1];
bool used[N];
int n,girl[N],boy[N],h[N],d[N],num;
bool find(int x){
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (used[y]) continue;used[y]=true;

        if (!girl[y]||find(girl[y])){
            boy[x]=y;girl[y]=x;return true;
        }
    }
    return false;
}
int main(){
    freopen("1963.in","r",stdin);
    n=read();
    for (int i=0;i<n;++i) d[i]=read();
    for (int i=n-1;i>=0;--i){
        data[++num].y=((i-d[i])%n+n)%n;data[num].next=h[i];h[i]=num;
        data[++num].y=((i+d[i])%n+n)%n;data[num].next=h[i];h[i]=num;
        if (data[num].y>data[num-1].y) swap(data[num].y,data[num-1].y);
    }
    //for(int i=1;i<=num;i+=2) printf("%d %d\n",data[i].y,data[i+1].y); 
    for (int i=n-1;i>=0;--i){
            memset(used,0,sizeof(used));if (!find(i)) {
                printf("No Answer");return 0;
            }
    }
    for (int i=0;i<n-1;++i) printf("%d ",boy[i]);printf("%d",boy[n-1]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值