杭电第七场题解

1004 Black Magic

给出n个方块,每个方块的左/右都可能是黑或白。将这些方块排成一列,如果两个相邻方块相连接的面都是黑色,那么这两个方块会连在一起。求连通块的最大/最小数量。(n<=10^5)

分类讨论,以下的L,R,E,B含义和题目中一样。对于连通块最多的情况,要让能够相连的方块对尽量少。可以发现,所有L可以全放在最左边,所有R可以全放在最右边,这样他们就不会和中间的方块相连,之后尽可能用E把B隔开即可。对于连通块最少的情况,要让能够相连的方块对尽可能多。可以先把所有B拼在一起,之后可以把一个L和一个R分为一组拼起来。注意如果有至少一组LR并且也有至少一块B的话,可以把一组LR拆开拼在B的两边,这样可以再减少一个连通块。
#include<bits/stdc++.h>
using namespace std;
template <typename tn>void read(tn &n){
    tn f=1,t=0;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)) t=t*10+ch-'0',ch=getchar();
    n=f*t;
}
inline void out(int x){
	if(x>9)out(x/10);
	putchar(x%10+'0');
}
int T,E,L,L2,R,R2,B,Ans;
int main(){
	read(T);
	while(T--){
		read(E),read(L),read(R),read(B);
		L2=L,R2=R,Ans=0;
		int com=min(L,R);
		if(com==0){
			Ans=E+L+R;
			if(Ans==E&&B>0)Ans++;
		}else{
			Ans=E+com;
			L-=com,R-=com;
			Ans+=L+R;
		}
		cout<<Ans<<" ";
		L=L2,R=R2;
		if(B==0)Ans=E+L+R;
		else{
			B-=1;
			Ans=L+R+1;
			if(B>=E)Ans+=2*E;
			else Ans+=E+B;
		}
		cout<<Ans<<endl;
	}
	return 0;
}

1008 Triangle Game

一个非退化三角形,三边边长分别为a,b,c。现 Kate Emilico 二人做游戏,每轮需要令三角形的一边长度减去一正整数,使这个三角形退化的一方负。 Kate 先手,双方均采用最优策略,问 Kate 是否会获胜。
结论是: Kate 获胜当且仅(a-1)^(b-1)^(c-1)不为0时
#include<bits/stdc++.h>
using namespace std;
template <typename tn>void read(tn &n){
    tn f=1,t=0;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)) t=t*10+ch-'0',ch=getchar();
    n=f*t;
}
inline void out(int x){
	if(x>9)out(x/10);
	putchar(x%10+'0');
}
int T;
long long a,b,c,d;
int main(){
	read(T);
	while(T--){
		read(a),read(b),read(c);
		a--,b--,c--;
		d=((a^b)^c);
		if(d)cout<<"Win"<<endl;
		else cout<<"Lose"<<endl; 
	}
	return 0;
}

1003 Counting Stickmen

给定一棵树,求其中有多少个人

为了方便描述 , 姑且将火柴人划分为头 , 手臂2个,手掌2个, 身体 , 腿2个的8条边 .
对于一个火柴人 , 我们枚举中间身体的那条边进行计数
假设身体靠头一侧的端点为x , 靠腿一侧的端点为y , 我们在x处计算头和手的方案, 在y处计算腿的方案 , 根据乘法原理 , 相乘即可得到火柴人的种数
#include<bits/stdc++.h>
using namespace std;
#define gc c=getchar()
#define r(x) read(x)
#define ll long long
template <typename tn>void read(tn &n){
    tn f=1,t=0;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)) t=t*10+ch-'0',ch=getchar();
    n=f*t;
}
inline void out(int x){
	if(x>9)out(x/10);
	putchar(x%10+'0');
}
const int N=1e7+7;
const int p=998244353;
vector<int>G[N];
int deg[N],s0[N],s1[N],s2[N];
inline int add(int a,int b){
    return (a+=b)>=p?a-p:a;
}
inline int sub(int a,int b){
    return (a-=b)<0?a+p:a;
}
inline ll calc(int x){
    return (ll)x*(x-1)/2%p;
}
int main(){
    int T;
    r(T);
    while(T--){
		int n;
		r(n);
	    for(int i=1;i<=n;++i)G[i].clear(),deg[i]=s0[i]=s1[i]=s2[i]=0;
    	for(int i=1;i<n;++i){
        	int u,v;r(u),r(v);
	        G[u].push_back(v);
    	    G[v].push_back(u);
        	++deg[u],++deg[v];
	    }
   		for(int x=1;x<=n;++x){
        	s0[x]=deg[x];
	        for(auto &y:G[x]){
    	        s1[x]=add(s1[x],deg[y]-1);
        	    s2[x]=add(s2[x],calc(deg[y]-1));
        	}
    	}
    	int ans=0;
    	for(int x=1;x<=n;++x){
 	       if(s0[x]>=4){
    	        for(auto &y:G[x]){
        	        if(s0[y]>=3){
            	        int head=sub(s0[x],3);
                	    int foot=sub(s0[y],1);
                    	int hand=sub(s1[x],foot);
                    	ans=add(ans,(ll)head*sub(calc(hand),sub(s2[x],calc(deg[y]-1)))%p*calc(foot)%p);
 	               }
    	        }
        	}
  		}
    	printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值