Codeforces Round #747 (Div. 2)

D - The Number of Imposters

题目大意

\(n\) 个人,他们只说真话或只说假话。给出 \(m\) 条信息,格式为 "第 \(i\) 个人说第 \(j\) 个人只说真话/假话"。请你判断最多的谎话者人数。如果矛盾输出 \(-1\)

解法

一个挺妙的转化是:当第 \(i\) 个人说第 \(j\) 个人只说真话时,他们一定是一种类型;同理,第 \(i\) 个人说第 \(j\) 个人只说假话时,他们的类型不同。

用带权并查集或建虚点都可以做。

代码

#include <cstdio>
#define print(x,y) write(x),putchar(y)

template <class T>
inline T read(const T sample) {
	T x=0; char s; bool f=0;
	while((s=getchar())>'9' or s<'0')
		f|=(s=='-');
	while(s>='0' and s<='9')
		x=(x<<1)+(x<<3)+(s^48),
		s=getchar();
	return f?-x:x;
}

template <class T>
inline void write(const T x) {
	if(x<0) {
		putchar('-'),write(-x);
		return;
	}
	if(x>9) write(x/10);
	putchar(x%10^48);
}

#include <iostream>
using namespace std;

const int maxn = 2e5+5;

int f[maxn],val[maxn];
int tot[maxn][2],n,m;
char s[20];

int Find(int x) {
	if(x==f[x]) return x; 
	int fa=Find(f[x]);
	val[x]^=val[f[x]];
	return f[x]=fa;
}

int main() {
	for(int T=read(9);T;--T) {
		n=read(9),m=read(9);
		for(int i=1;i<=n;++i)
			f[i]=i,val[i]=0,
			tot[i][0]=tot[i][1]=0;
		bool flag=false;
		for(int i=1;i<=m;++i) {
			int x=read(9),y=read(9);
			int u=Find(x),v=Find(y);
			scanf("%s",s+1);
			bool op=(s[1]=='i');
			if(u^v) {
				f[u]=v;
				val[u]=val[x]^val[y]^op;
			}
			else if(val[x]^val[y]^op)
				flag=true;
		}
		if(flag) {
			puts("-1");
			continue;
		}
		for(int i=1;i<=n;++i)
			++tot[Find(i)][val[i]];
		int ans=0;
		for(int i=1;i<=n;++i)
			if(Find(i)==i)
				ans+=max(tot[i][0],tot[i][1]);
		print(ans,'\n');
	}
	return 0;
}

E2 - Rubik's Cube Coloring (hard version)

解法

容易发现,当一个点固定颜色后,它只会影响从它开始往上一条链的点。其它的点的颜色种数乘上 \(4\) 的幂次即可。由于树高只有 \(60\),所以最多有 \(60n=120000\) 个点被影响。令 \(dp_{i,j}\) 为第 \(i\) 个点颜色为 \(j\) 的染色方案数,只考虑被影响点即可。

优化 \(\mathtt{dp}\) 状态数是一种好方法。

代码

#include <cstdio>
#define print(x,y) write(x),putchar(y)

template <class T>
inline T read(const T sample) {
	T x=0; char s; bool f=0;
	while((s=getchar())>'9' or s<'0')
		f|=(s=='-');
	while(s>='0' and s<='9')
		x=(x<<1)+(x<<3)+(s^48),
		s=getchar();
	return f?-x:x;
}

template <class T>
inline void write(const T x) {
	if(x<0) {
		putchar('-'),write(-x);
		return;
	}
	if(x>9) write(x/10);
	putchar(x%10^48);
}

#include <map>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;

const int mod = 1e9+7;

int k,n,pin,dp[2005*60][6],co[2005];
ll a[2005];
string s;
map <ll,int> id; 
map <string,int> mp;
vector <int> adj[8];

int qkpow(int x,ll y) {
	y=(y%(mod-1)+mod-1)%(mod-1);
	int r=1;
	while(y) {
		if(y&1) r=1ll*r*x%mod;
		x=1ll*x*x%mod; y>>=1;
	}
	return r;
}

inline int inc(int x,int y) {
	return x+y>=mod?x+y-mod:x+y;
}

int dfs(ll o,int c) {
	int ind=id[o];
	if(~dp[ind][c]) 
		return dp[ind][c];
	if(ind<=n and (c^co[ind]))
		return 0;
	int ans1=0,ans2=0;
	for(auto v:adj[c]) {
		if(id.count(o<<1))
			ans1 = inc(ans1,dfs(o<<1,v));
		if(id.count(o<<1|1))
			ans2 = inc(ans2,dfs(o<<1|1,v));
	}
	if(!id.count(o<<1)) ans1=1;
	if(!id.count(o<<1|1)) ans2=1;
	return dp[ind][c]=1ll*ans1*ans2%mod;
}

int main() {
	mp["white"]=0;
	mp["yellow"]=1;
	mp["green"]=2;
	mp["blue"]=3;
	mp["red"]=4;
	mp["orange"]=5;
	for(int i=0;i<6;++i)
		for(int j=0;j<6;++j)
			if((i>>1)^(j>>1))
				adj[i].push_back(j);
	memset(dp,-1,sizeof dp);
	k=read(9),pin=n=read(9);
	for(int i=1;i<=n;++i) {
		a[i]=read(9ll);
		cin>>s; co[i]=mp[s];
		id[a[i]]=i;
	}
	for(int i=1;i<=n;++i)
		for(ll j=a[i]>>1;j;j>>=1)
			if(!id.count(j))
				id[j]=++pin;
	int ans=0;
	for(int i=0;i<6;++i)
		ans = inc(ans,dfs(1,i)); 
	print(1ll*ans*qkpow(4,(1ll<<k)-pin-1)%mod,'\n');
	return 0;
} 
原文地址:https://www.cnblogs.com/AWhiteWall/p/12340511.html