Luogu P5603 小C与桌游

题目链接https://www.luogu.org/problem/P5603?contestId=22461

题目描述

这个桌游的地图可以被抽象成一个 n 个点,m 条边的有向无环图不保证连通),小C在这个地图上行走,小C能走到某个点当且仅当能够到达这个点的所有点都已经被小C走到。小C会走到每个点恰好 11 次,并且他能走到哪些点与他当前所在的点没有关系(即可以走到与当前所在的点没有连边的点,只要满足之前的条件)。

\[小C每走到一个标号比之前走到的点都大的点,他就会有 \frac{1}{2} ​ 的概率从对手那里拿到 1 块筹码,有 \frac{1}{2} ​ 的概率给对手 1 块筹码 \]

双方初始各有 19198101919810 个筹码。

小C的运气时好时坏,所以他希望你帮他计算出:

  • 在最优情况下,即他每次都能从对手那里拿到筹码时,他采取最优的行走方式能得到的筹码数。
  • 在最劣情况下,即对手每次都能从他那里拿到筹码时,他采取最优的行走方式会失去的筹码数。

框中是废话

在月赛中是IOI赛制,于是蒟蒻我一打完就交了上去,“咣”拿了4分。一看,原来是指针打错了,改好之后又是“咣”的一声拿了46分。之后蒟蒻我苦思冥想(狂膜大佬hsm)终于A了。

在题目中我们可以看出在最优情况下,我们维护一个小根堆,从题目可以看出我们每次去出最小的节点进行dfs,就可以使得到的硬币最多。

在题目中我们可以看出在最坏情况下,一开始因为最优情况,我因为只要维护一个大根堆就可以了于是,“咣”的一下只有46分。仔细研究题目可以发现我们要取出当前可以达到所有小于当前已到达的最大节点的点。

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;

const int N = 5e5 + 10;
const int Max = 1919810;

int n, m, ans, tot, num;
int head[N], kk[N];

priority_queue <int>q;

struct nod{
	int ru1, id, ru2;
}a[N];

struct Edg{
	int to, nxt;
}e[N];

template <typename T>
inline void read(T &x){
	x = 0;
	char c = getchar();
	T op = 1;
	for(; c < '0' || c > '9'; c = getchar())
		if(c == '-')	op = -1;
	for(; c <= '9' && c >= '0'; c = getchar())
		x = (x << 3) + (x << 1) + c - '0';
	x *= op;
}

inline void add(int x, int y){
	e[++tot].to = y;
	e[tot].nxt = head[x];
	head[x] = tot;
}

inline void dfs1(){
	num = -1;
	for(int i = 1; i <= n; ++i)
		if(!a[i].ru1)	q.push(-i);
	while(!q.empty()){
		int x = q.top();
		q.pop();
		x *= -1;
		if(x > num)	num = x, ++ans;
		for(int i = head[x]; i; i = e[i].nxt){
			a[e[i].to].ru1--;
			if(!a[e[i].to].ru1)	q.push(-e[i].to);
		}
	}
	printf("%d\n", ans > Max ? Max : ans);
	ans = 0;
}

inline void dfs2(){
	num = -1;
	for(int i = 1; i <= n; ++i)
		if(!a[i].ru2)	q.push(i);
	while(!q.empty()){
		int x = q.top();
		q.pop();
		tot = 0;
		if(x > num)	num = x, ++ans;
		for(int i = head[x]; i; i = e[i].nxt){
			a[e[i].to].ru2--;
			if(!a[e[i].to].ru2)	q.push(e[i].to);
		}
		while(!q.empty()){
			int s = q.top();
			q.pop();
			if(s > num)	{kk[++tot] = s; continue;}
			for(int i = head[s]; i; i = e[i].nxt){
				a[e[i].to].ru2--;
				if(!a[e[i].to].ru2)	q.push(e[i].to);
			}
		}
		for(int i = 1; i <= tot; ++i)
			q.push(kk[i]);
	}
	printf("%d\n", ans > Max ? Max : ans);
}

int main(){
	read(n), read(m);
	for(int i = 1; i <= m; ++i){
		int x, y;
		read(x), read(y);
		add(x, y);
		a[y].ru1++, a[y].ru2++;
	}
	dfs1();
	dfs2();
	return 0;
}
posted @ 2019-11-05 21:18  ZmeetL  阅读(134)  评论(0编辑  收藏  举报