题解 CF1344C Quantifier Question

题目链接

首先,因为小于的关系是可传递的,所以对于一组限制((j_i,k_i)),我们考虑连一条有向边(j_i o k_i)。这样能建出一个图。显然。如果图上有环,肯定无解,答案是(-1)。而只要图上没有环,那么一定有解,因为至少全填(exist)的时候是成立的。所以以下只考虑一个DAG的情况。

接下来,要让(forall)尽可能多。这就需要你细细地品这个关系了。

你会发现,每个(Q_i),不是平等的。例如,如果是(x_1<x_2,x_3<x_2),答案就是(Q_1=forall,Q_2=exist,Q_3=exist)。但如果是(x_1<x_3,x_2<x_3),答案就可以变成(Q_1=forall,Q_2=forall,Q_3=exist)。(备注:这个例子其实就是样例3)。你可以看出,在两个一模一样的结构里,仅仅是编号不同((2)(3)交换了),就可以改变(forall)的数量,所以从前往后每个编号是有区别的、不平等的。

进而发现,对于(i<j),只要(i)能到达(j)(j)能到达(i),那么(Q_j)一定等于(exist),不论(Q_i)等于什么。那既然不论我填(forall)还是(exist),影响是一样的,我当然尽可能多填(forall)。也就是用这样一种贪心的思想:能填(forall)就绝不填(exist)

于是问题转化为,按编号从小到大,依次标记每个节点。对当前节点(i),如果所有【(i)能到达的】和【能到达(i)的】节点都未被标记,则(Q_i=forall),否则(Q_i=exist)

当然,你会发现,对所有【(i)能到达的】和【能到达(i)的】节点进行查询,非常困难。转化一下,变成修改操作,也同样困难!如果你这么想这个问题,那你就是用了“数据结构”的思维,总想在过程进行中,大力维护一些什么。但其实,还有另一种思维,也就是“DP”的思维。不在过程中维护,而是预处理出来:用递推的方式预处理出来,不断从已知的,推出未知的。

具体来说,可以现在DAG上正着跑一遍拓扑排序,就能递推出【能到达每个点的】最小编号。再在反图上跑一遍拓扑排序,就能递推出【每个点能到达的】最小编号。

时间复杂度(O(n+m))

参考代码:

//problem:
#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define mk make_pair
#define lob lower_bound
#define upb upper_bound
#define fi first
#define se second
#define SZ(x) ((int)(x).size())

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;

template<typename T>inline void ckmax(T& x,T y){x=(y>x?y:x);}
template<typename T>inline void ckmin(T& x,T y){x=(y<x?y:x);}

const int MAXN=2e5;
int n,m,ind[MAXN+5],ind_rev[MAXN+5];
int dp[MAXN+5],dp_rev[MAXN+5];
vector<int>G[MAXN+5],RG[MAXN+5];

char ans[MAXN+5];
int maxnum;
int main() {
	cin>>n>>m;
	for(int i=1;i<=m;++i){
		int u,v; cin>>u>>v;
		G[u].pb(v); RG[v].pb(u);
		ind[v]++; ind_rev[u]++;
	}
	queue<int>q;
	for(int i=1;i<=n;++i){
		dp[i]=i;
		if(!ind[i]){
			q.push(i);
		}
	}
	while(!q.empty()){
		int u=q.front(); q.pop();
		for(int i=0;i<SZ(G[u]);++i){
			int v=G[u][i];
			ind[v]--;
			ckmin(dp[v],dp[u]);
			if(!ind[v]){
				q.push(v);
			}
		}
	}
	for(int i=1;i<=n;++i)
		if(ind[i]){
			cout<<"-1"<<endl;
			return 0;
		}
	for(int i=1;i<=n;++i){
		dp_rev[i]=i;
		if(!ind_rev[i]){
			q.push(i);
		}
	}
	while(!q.empty()){
		int u=q.front(); q.pop();
		for(int i=0;i<SZ(RG[u]);++i){
			int v=RG[u][i];
			ind_rev[v]--;
			ckmin(dp_rev[v],dp_rev[u]);
			if(!ind_rev[v]){
				q.push(v);
			}
		}
	}
	for(int i=1;i<=n;++i){
		if(dp[i]<i || dp_rev[i]<i){
			ans[i]='E';
		}
		else{
			ans[i]='A';
			maxnum++;
		}
	}
	cout<<maxnum<<endl;
	for(int i=1;i<=n;++i)
		cout<<ans[i];
	cout<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/dysyn1314/p/13388056.html