Atcoder Grand Contest -016 E - Poor Turkeys

版权声明:_ https://blog.csdn.net/lunch__/article/details/82947593

题意

  • n n 个人,每个人依次选择 u , v u, v 中的一个点删除,如果两个点都不删除这个人就不操作,如果有一个点被删除,他会选择删除另一个,问有多少对点存在一种情况使他们都没被删除

首先发现这个东西不是很好做

我们倒过来看 定义一个集合 S i S_i

这个集合就代表如果 i i 号点存在

哪些点一定要替 i i 号点被删除

我们倒过来加边的时候和 i i 号相连的肯定要替 i i

所以在这个之前他们就不能删 如果删了肯定是无解的

那么把再把他们相连的点加入集合 加入集合的点都是不能删的

我们就得到了每个点的 S S 集合

存在一种情况让两个点都不被删除的充要条件是

两个点的 S S 集合没有交集

如果两个集合的 S S 集合有交集的话

那么就会存在一个点既要替第一个点被删除 又要替第二个点被删

但是如果它替第一个点被删的话

第二个点就会缺少替的就会被删除

反之亦然 那么就做完了

我们统计 S S 没有交集的点对个数就好了

可以用 b i t s e t bitset 来优化 复杂度 O ( n 3 ω ) O(\frac{n^3}{\omega})

Codes

#include<bits/stdc++.h>
#include<bits/extc++.h>

#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
#define For(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define FOR(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define debug(x) cout << #x << " = " << x << endl
#define mem(a, b) memset(a, b, sizeof(a))
#define cpy(a, b) memcpy(a, b, sizeof(a))
#define min(a, b) (a < b ? a : b)
#define max(a, b) (b < a ? a : b)
#define inf (0x3f3f3f3f)
#define INF (1e18)
#define pb push_back
#define mp make_pair
#define x first
#define y second

typedef unsigned long long ull;
typedef unsigned int uint;
typedef long long ll;
typedef std::pair<ll, int> PLI;
typedef std::pair<int, int> PII;
typedef long double ldb;
typedef double db;

namespace IO {
#define getc() ((S_ == T_) && (T_ = (S_ = Ch_) + fread(Ch_, 1, Buffsize, stdin), S_ == T_) ? 0 : *S_ ++)
#define putc(x) *nowps ++ = (x)
	const uint Buffsize = 1 << 15, Output = 1 << 23;
	static char Ch_[Buffsize], *S_ = Ch_, *T_ = Ch_;
	static char Out[Output], *nowps = Out;
	inline void flush(){fwrite(Out, 1, nowps - Out, stdout); nowps = Out;}
	template<class T>inline void read(T &_) {
		_ = 0; static char __; T ___ = 1;
		for(__ = getc(); !isdigit(__); __ = getc()) if(__ == '-') ___ = -1;
		for(; isdigit(__); __ = getc()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
		_ *= ___;
	}
	template<class T>inline void write(T _, char __ = '\n') {
		if(!_) putc('0');
		if(_ < 0) putc('-'), _ = -_;
		static uint sta[111], tp;
		for(tp = 0; _; _ /= 10) sta[++ tp] = _ % 10;
		for(; tp; putc(sta[tp --] ^ 48)); putc(__);
	}
	template<class T>inline bool chkmax(T &_, T __) {return _ < __ ? _ = __, 1 : 0;}
	template<class T>inline bool chkmin(T &_, T __) {return _ > __ ? _ = __, 1 : 0;}
}

using namespace std;
using namespace IO;

const int N = 400 + 10;
const int M = 5e4 + 10;

bitset<N> a[N];

int n, m, ans;

struct Edge {
	int x, y;
}E[M];

int main() {
#ifdef ylsakioi
	file("c");
#endif
	read(n), read(m);
	For(i, 1, m) read(E[i].x), read(E[i].y);
	For(i, 1, n) {
		a[i][i] = 1;
		FOR(j, m, 1) if(a[i][E[j].x] || a[i][E[j].y]) {
			if(a[i][E[j].x] && a[i][E[j].y]) {
				a[i].set(); break;
			}
			if(a[i][E[j].x]) a[i][E[j].y] = 1;
			if(a[i][E[j].y]) a[i][E[j].x] = 1;
		}
	}
	For(i, 1, n) For(j, 1, n) if(!(a[i] & a[j]).any()) ++ ans;
	write(ans >> 1);
	return flush(), 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/82947593