• BZOJ1562: [NOI2009]变换序列


    BZOJ1562: [NOI2009]变换序列

    Description

    Input

    Output

    Sample Input

    5
    1 1 2 2 1

    Sample Output

    1 2 4 0 3

    HINT

    30%的数据中N≤50;
    60%的数据中N≤500;
    100%的数据中N≤10000。


    题解Here!

    题面不是很好懂。。。
    简化一下:每个数$i$能与$(i+d_i)\%N,(i-d_i+N)\%N$匹配,问每个数匹配后某位置匹配的原来的数是什么。
    很明显建完边然后二分图匹配。。。
    二分图匹配丢给了匈牙利。。。
    但是那个字典序最小怎么整?
    我们可以将每个数的匹配中,小的放前面,大的放后面,然后倒着做一遍匈牙利。
    这时我们发现现有的匹配覆盖了原有的匹配。
    并且字典序更小!
    所以这么做是对的。
    复杂度是非常松的$O(n^2)$。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define MAXN 10010
    using namespace std;
    int n,T,c=1;
    int head[MAXN],val[MAXN],f[MAXN],g[MAXN],vis[MAXN],map[MAXN][2];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    bool find(int x){
    	for(int k=0;k<=1;k++){
    		if(vis[map[x][k]]==T)continue;
    		int v=map[x][k];
    		vis[v]=T;
    		if(f[v]==-1||find(f[v])){
    			f[v]=x;g[x]=v;
    			return true;
    		}
    	}
    	return false;
    }
    void work(){
    	T=1;
    	for(int i=n-1;i>=0;i--){
    		if(!find(i)){
    			printf("No Answer");
    			return;
    		}
    		T++;
    	}
    	for(int i=0;i<n-1;i++)printf("%d ",g[i]);
    	printf("%d",g[n-1]);
    }
    void init(){
    	int u,v,w;
    	n=read();
    	memset(f,-1,sizeof(f));
    	for(int i=0;i<n;i++){
    		w=read();
    		u=(i-w+n)%n;v=(i+w)%n;
    		if(u>v)swap(u,v);
    		map[i][0]=u;map[i][1]=v;
    	}
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    
  • 相关阅读:
    正则表达式30分钟入门教程
    oracle常用的字符和字符串处理类函数
    [转载]C#实现软件自动更新思路
    ORACLE函数介绍
    xml 文件操作类
    oracle 主键生成策略
    wmsys.wm_concat、sys_connect_by_path、自定义函数实现行列转换
    NSIS开始...
    Oracle分析函数详述
    常用正则表达式收集
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9691654.html
Copyright © 2020-2023  润新知