Educational Codeforces Round 72 (Rated for Div. 2)

A - Creating a Character

题意:给出智慧值n、力量值m和经验值p,经验值要分配给智慧值和力量值,但是要求智慧值要大于力量值,问有几种分配方法。
题解:
第一种情况:当n > m+p 时,无论p怎么给都符合要求,方案数p+1
第二种情况:当 m > n+p时,即使全部p都给n都不符合要求,方案数为0
第三种情况:设经验值的分配一共有p+1种分法,设有x点经验值分配给n,则n + x > m + (p+1-x) 所以 x > (m+p+1-n)/2 ,所以满足条件的分配法有 p+1 - (m+p-n)/2 = (p+1-m+n)/2

#include <cstdio>
int main(){
	int t ; 
	scanf ("%d",&t) ;
	while(t --){
		int n , m , p ; 
		scanf ("%d%d%d",&n,&m,&p) ;
		if (n > m+p)	printf ("%d\n",p+1) ;
		else if (m > n+p)	printf ("0\n") ;
		else	printf ("%d\n",(p+1+n-m)/2) ;
	}
	
	return 0 ;
} 

将三种情况分解为取最大最小值就是下面这样了(大佬的代码就是精简)
因为第二种情况算出来是负数,所以与第三种取最大值,当m+p < n 的情况下,方案数为p+1(怎么给都行),所以与前面的最大值取最小值即可。

#include <algorithm> 
using namespace std ; 
int main(){
	int t ; 
	scanf ("%d",&t) ; 
	while(t --){
		int n , m , p ; 
		scanf ("%d%d%d",&n,&m,&p) ; 
		printf ("%d\n",min (max( (n-m+p+1)/2 , 0 ) , p+1)) ;
	}
	return 0 ; 
}
B. Zmei Gorynich

题意:一只怪兽有n只手,现在有m把剑,每把剑都有属性一次能砍去怪兽的a只手,如果怪兽当前还有手会恢复b只手,当怪兽的手为0时怪兽死亡。
题解:在输入的时候记录砍去和恢复相差最大的差,还有一次砍去最多的,然后先减去最多的,若已经小于等于0即一次就成功,若没有就再计算

#include <cstdio>
#include <algorithm>
using namespace std ; 
const int N = 105 ;  
int main(){
	int t ; 
	scanf ("%d",&t) ; 
	while(t --){
		int n , m , a , b ; 
		scanf ("%d%d",&n,&m) ;
		int sub = -1e9 , maxd = 0 ; 
		for (int i = 0 ; i < n ; ++ i){
			scanf ("%d%d",&a,&b) ;
			if (sub < a-b)	sub = a-b ;
			if (a > maxd)	maxd = a ;  
		}	
		m -= maxd ; 
		if (m <= 0){
			printf ("1\n") ;
			continue ; 
		}	
		if (sub <= 0)	{
			printf ("-1\n") ;
			continue ; 
		}
		printf ("%d\n",(m+sub-1)/sub+1) ;	//因为手的数量要小于等于0,所以加上sub,又因为怕刚好sub会多算一次所以减去1再除,最后的加一是减去之前砍掉最多的一次
	}
	return 0 ; 
}
C. The Number Of Good Substrings

题意:给出一串01字符串,如果字符串长度等于二进制数则为好的字符串例如:f(011)=3 f(0100)=4,f(00101)=5 都是好的字符串,问给定的字符串中含有多少个好的字符子串。
题解:计算每个数的前导0个数,遇到1就计算当前数的十进制值,最后判断。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std ; 
int main(){
	int t ; 
	cin >> t ; 
	while(t --){
		string str ; 
		cin >> str ; 
		int len = str.length() ; 
		int zero = 0 , ans = 0 ; 
		for (int i = 0 ; i < len ; ++ i){
			if (str[i] == '0')	++zero ; //计算前导0个数
			else{
				int sum = 0 , cnt = 0 ;	//当前数的值和字符串长度 
				for (int j = i ; j < len ; ++ j){
					sum = 2*sum + str[j] - '0' ; 
					++ cnt ; //长度
					if (sum >= len + 2)		break ;	//当前数已经大于字符串长度了,跳出循环 
					if (cnt + zero >= sum)	++ ans ;   
				}
				zero = 0 ; 
			}
		}
		printf ("%d\n",ans) ; 
	}
	return 0 ; 
}
D - Coloring Edges

题意:给边染色使得同种颜色的边不能成环,问最少需要多少种颜色并且打印出染色的方案。
题解:先判断是否成环,若不成环就全部染成1,若成环就让编号从大指到小的染为2,从小到大的染为1。然后判断是否成环用到了拓扑排序,将入度为0 的入队然后接下来就是拓扑排序了,最后判断出队的点数是否等于给定的点数,如果是就不成环,如果不是就成环。

#include <cstdio>
#include <vector>
#include <queue>
using namespace std ;
const int N = 5005 ; 
vector<int> graph[N] ;  
bool vis[N] ; 
int in[N] ; 
struct node{
	int u , v ;
}edge[N] ;
int n , m ;  
bool isCirle(){
	int cnt = 0 ; 
	queue<int> q ; 
	for (int i = 1 ; i <= n ; ++ i)
		if (in[i] == 0)
			q.push(i) ;
	while(!q.empty()){
		int head = q.front() ;
		++ cnt , q.pop() ;
		for (int i = 0 ; i < graph[head].size() ; ++ i){
			int t = graph[head][i] ; 
			-- in[t] ; 
			if (in[t] == 0)
				q.push(t) ; 
		}
	}
	return (n==cnt) ; 
}
int main(){
	scanf ("%d%d",&n,&m) ; 
	for (int i = 0 ; i < m ; ++ i){
		int u , v ; 
		scanf ("%d%d",&u,&v) ; 
		edge[i] = {u,v} ;
		++ in[v] ;  
		graph[u].push_back(v) ; 
	}
	if (isCirle()){
		printf ("1\n") ;
		for (int i = 0 ; i < m ; ++ i)
			printf ("1 ") ;
	}
	else{
		printf ("2\n") ;
		for (int i = 0 ; i < m ; ++ i)
			printf ("%d ",edge[i].u<edge[i].v?1:2) ;
	}
	return 0 ; 
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值