这题CF给的难度是2000,但我感觉没这么高啊……
题目链接:CF原网
题目大意:有两个正整数序列 $a,b$,长度分别为 $n,m$。给出所有 $a_i$ 和 $b_j(1\le i\le n,1\le j\le m)$ 的大小关系(大于,小于或者等于),请构造出符合条件的 $a$ 和 $b$。如果无解,输出NO。如果有多个解,输出 $a,b$ 中最大元素最小的方案。
$1\le n,m\le 1000$。
这题一眼差分约束。但是看着没有具体的数字……(主要是我不会打)
然而二眼就是拓扑排序。每次将小的数往大的数连边,然后跑拓扑排序。规定一开始入度为 $0$ 的点的值为 $1$,然后拓扑时简单转移一下就好了。如果有点没有被遍历到(就是大小关系有环),那么显然无解。
不过有相同的元素……看着不好搞……
算了,直接上并查集。把相同的元素压到一个集合,然后把这些点看成一个点操作。
时间复杂度 $O(nm)$。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> PII; const int maxn=1000100; #define MP make_pair #define PB push_back #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define ROF(i,a,b) for(int i=(a);i>=(b);i--) #define MEM(x,v) memset(x,v,sizeof(x)) inline int read(){ char ch=getchar();int x=0,f=0; while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return f?-x:x; } int n,m,el,head[2020],to[maxn],nxt[maxn],q[2020],h=1,r,deg[2020],fa[2020],val[maxn]; char mp[1010][1010]; bool vis[2020]; inline void add(int u,int v){ to[++el]=v;nxt[el]=head[u];head[u]=el;deg[v]++; } int getfa(int x){ return x==fa[x]?x:fa[x]=getfa(fa[x]); } void unite(int x,int y){ x=getfa(x);y=getfa(y); if(x!=y) fa[x]=y; } int main(){ n=read();m=read(); FOR(i,1,n) scanf("%s",mp[i]+1); FOR(i,1,n+m) fa[i]=i; FOR(i,1,n) FOR(j,1,m) if(mp[i][j]=='=') unite(i,j+n); FOR(i,1,n) FOR(j,1,m){ if(mp[i][j]=='<') add(getfa(i),getfa(j+n)); if(mp[i][j]=='>') add(getfa(j+n),getfa(i)); } FOR(i,1,n+m) if(i==getfa(i) && !deg[i]) q[++r]=i,val[i]=1,vis[i]=true; while(h<=r){ int u=q[h++]; for(int i=head[u];i;i=nxt[i]){ int v=to[i]; if(vis[v]) continue; if(!--deg[v]){ vis[v]=true; val[v]=val[u]+1; q[++r]=v; } } } FOR(i,1,n+m) if(i==getfa(i) && !vis[i]) return puts("No"),0; puts("Yes"); FOR(i,1,n) printf("%d ",val[getfa(i)]); puts(""); FOR(i,1,m) printf("%d ",val[getfa(i+n)]); }View Code