zoukankan      html  css  js  c++  java
  • 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;
    } 
    
  • 相关阅读:
    UVALive 3664:Guess(贪心 Grade E)
    uva 1611:Crane(构造 Grade D)
    uva 177:Paper Folding(模拟 Grade D)
    UVALive 6514:Crusher’s Code(概率dp)
    uva 11491:Erasing and Winning(贪心)
    uva 1149:Bin Packing(贪心)
    uva 1442:Cave(贪心)
    学习 linux第一天
    字符编码问题
    orm 正向查询 反向查询
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12340511.html
Copyright © 2011-2022 走看看