【ZJCPC2022 第19届 浙江省赛】The 19th Zhejiang Provincial Collegiate Programming Contest

目录

A. JB Loves Math

B.JB Loves Comma

C. JB Wants to Earn Big Money

L. Candy Machine

G. Easy Glide

M. BpbBppbpBB

I. Barbecue

A. JB Loves Math

思路:
a b
要使a = b
则使b-a = 0
1.b-a = 正偶
1.1 (b-a)/2为奇数    则b-a+(b-a)/2+(b-a)/2 = 0
1.2 (b-a)/2为偶数      b-a + (b-a+1)+(b-a+1) - (b-a+2)= 0


2.a-b = 正奇
a-b - (a-b+1) + 1 = 0


3.其他情况比较简单就不讨论了

#include<bits/stdc++.h>
using namespace std ;
const int maxn = 1e3 + 10 ;
const int inf = 0x3f3f3f3f ;
void deal(){
	int a , b ; cin >> a >> b ;
	if(a == b)cout << 0 << endl ;
	else if(a > b){
		if((a-b) % 2 == 0){
			cout << 1 << endl ; 
		}else{
			cout << 2 << endl ; 
		}
	}else{
		if((b - a) % 2 == 1){
			cout << 1 << endl ; 
		}else{
			if((b-a)/2 % 2 == 1)cout << 2 << endl ;
			else cout << 3 << endl ; 
		}
	}
}
int main(){
	int t ; cin >> t ;
	while(t--)deal() ;
	return 0 ;
}

B.JB Loves Comma

#include<bits/stdc++.h>
using namespace std ;
const int maxn = 1e3 + 10 ;
const int inf = 0x3f3f3f3f ;
void deal(){
	string s ; cin >> s ;
	for(int i = 0 ; i < s.size() ; i++){
		cout << s[i] ;
		if(i >= 2 && s.substr(i-2 , 3) == "cjb"){
			cout << "," ;
		}
	}
}
int main(){
	deal() ;
	return 0 ;
}

C. JB Wants to Earn Big Money

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e5 + 10 ;
const int inf = 0x3f3f3f3f ;
void deal(){
	int n , m , x , ans = 0 ; cin >> n >> m >> x ;
	for(int i = 0 ; i < n ; i++){
		int v ; cin >> v ;
		if(v >= x)ans++ ;
	}
	for(int i = 0 ; i < m ; i++){
		int v ; cin >> v ;
		if(v <= x)ans++ ;
	}
	cout << ans << endl ;
}
int main(){
	deal() ;
	return 0 ;
}

L. Candy Machine

思路:假设最终选择的集合的平均数不超过 k。 为使平均数不超过 k,应将 ≤ k 的数全部选入,然后贪心选 择 > k 的部分中最小的若干个数。 因此将 N 个数从小到大排序后,最优解一定是一个前缀。 枚举每个前缀,二分出严格大于平均数的数字个数。

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e6 + 10 ;
const int inf = 0x3f3f3f3f ;
int a[maxn] ;
double sum[maxn] ;
void deal(){
	int n ; scanf("%d" , &n) ;
	for(int i = 1 ; i <= n ; i++){
		scanf("%d" , &a[i]) ;
	}
	sort(a+1 , a+1+n) ;
	for(int i = 1 ; i <= n ; i++){
		sum[i] = a[i] + sum[i-1] ;
	}
	int ans = 0 ;
	for(int i = 1 ; i <= n ; i++){
		double avg = sum[i] / i ;
		int l = 1 , r = i ;
		while(l < r){
			int mid = l+r >> 1 ;
			if(a[mid] > avg)r = mid ;
			else l = mid+1 ;
		}
		ans = max(ans , i-l+1) ;
	}
	cout << ans << endl ;
}
int main(){
	deal() ;
	return 0 ;
}

G. Easy Glide

思路:用结构体存储每一个点,开始点是0点,结束点是n+1点,然后计算i点到j点所花的时间,再用dijkstra算法计算最短时间

注意点:出发点不能加速;数据要开long long。

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e3 + 10 ;
const int inf = 0x3f3f3f3f ;
struct node{
	ll x , y ;
}p[maxn];
double g[maxn][maxn] , d[maxn] ;
int vis[maxn] ;
void deal(){
	int n ; cin >> n ; 
	fill(d , d+maxn , inf) ;
	for(int i = 1 ; i <= n ; i++){
		ll u , v ; scanf("%lld %lld" , &u , &v) ;
		p[i].x = u , p[i].y = v ;
	}
	scanf("%lld %lld %lld %lld" , &p[0].x , &p[0].y , &p[n+1].x , &p[n+1].y) ;
	ll v1 , v2 ; 
	scanf("%lld %lld" , &v1 , &v2) ;
	for(int i = 0 ; i <= n+1 ; i++){
		for(int j = 0 ; j <= n+1 ; j++){
			if(i == j){
				g[i][j] = 0 ;
				continue ;
			}
			double dis = sqrt(abs((p[i].x - p[j].x) * (p[i].x - p[j].x)) + abs((p[i].y - p[j].y) * (p[i].y - p[j].y))) ;
			if(v2*3 >= dis && i != 0){
				g[i][j] = dis/v2 ;
			}else if(v2*3 < dis && i != 0){
				g[i][j] = 3+(dis-v2*3)/v1 ;
			}else{
				g[i][j] = dis/v1 ;
			}
		}
	}
	d[0] = 0 ;
	for(int i = 0 ; i <= n+1 ; i++){
		int t = -1 , mind = 0 ;
		for(int j = 0 ; j <= n+1 ; j++){
			if(!vis[j]){
				if(t == -1 || mind > d[j]){
					t = j ;
					mind = d[j] ;
				}
			}
		}
		if(t == -1)break ;
		vis[t] = 1 ;
		for(int j = 0 ; j <= n+1 ; j++){
			if(!vis[j]){
				d[j] = min(d[j] , d[t]+g[t][j]) ;
			}
		}
	}
	printf("%.6lf\n" , d[n+1]) ;
}
int main(){
	deal() ;
	return 0 ;
}

M. BpbBppbpBB

假设黑色格子数为cnt1 , 白色格子组成的洞数为cnt2 , 而C印章数为a , S印章数为b

C印章的黑色格子数为146,S印章的黑色格子数为100 

C印章的白洞为2,S印章的白洞为1

则a*146 + b*100 = cnt1 , a*2+b = cnt2

所以只要求出cnt1,cnt2,然后解方程就好了

如何判断是否是白洞呢?

我是先用bfs计算出一个白色连通块中白色格子的个数 == 12,且该白色连通块的形状是4*4的(可以自己比划一下,用俩个印章拼接是组不出4*4的白色连通块且其中白色格子的个数 == 12的)

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e3 + 10 ;
const int inf = 0x3f3f3f3f ;
char c[maxn][maxn] ;
int vis[maxn][maxn] ;
int X[4] = {1 , 0 , -1 , 0} ;
int Y[4] = {0 , 1 , 0 , -1} ;
int n , m ;
struct node {
	int x , y ;
};
bool bfs(int x , int y){
	queue<node > q ;
	node temp ;
	temp.x = x , temp.y = y ;
	q.push(temp) ;
	vis[x][y] = 1 ;
	int cnt = 0 ;
	int maxx = x , maxy = y , minx = x , miny = y ; 
	while(!q.empty()){
		node top = q.front() ;
		q.pop() ;
		cnt++ ;
		for(int i = 0 ; i < 4 ; i++){
			int nx = top.x + X[i] ;
			int ny = top.y + Y[i] ;
			if(vis[nx][ny] == 0 && c[nx][ny] == '.'){
				if(nx >= 0 && nx < n && ny >= 0 && ny < m){
					vis[nx][ny] = 1 ;
					temp.x = nx , temp.y = ny ;
					q.push(temp) ;
					maxx = max(maxx , nx) ;
					maxy = max(maxy , ny) ;
					minx = min(minx , nx) ;
					miny = min(miny , ny) ;
				}
			}
		}
	}
	if(cnt == 12 && maxx - minx == 3 && maxy - miny == 3)return true ;
	else return false ;
}
void deal(){//C:146 S:100
	cin >> n >> m ;
	int cnt1 = 0 , cnt2 = 0 ;
	for(int i = 0 ; i < n ; i++){
		scanf("%s" , c[i]) ;
		for(int j = 0 ; j < m ; j++){
			if(c[i][j] == '#'){
				cnt1++ ;
			}
		}
	}
	for(int i = 0 ; i < n ; i++){
		for(int j = 0 ; j < m ; j++){
			if(c[i][j] == '.'){
				if(bfs(i , j))cnt2++ ;
			}
		}
	}
	for(int i = 0 ; i <= cnt1/146 ; i++){
		if((cnt1 - 146*i) % 100 == 0){
			for(int j = 0 ; j <= (cnt1 - 146*i)/100 ; j++){
				if(i*2 + j == cnt2){
					cout << i << " " << j << endl ;
					return ;
				}
			}
		}
	}
}
int main(){
	deal() ;
	return 0 ;
}

I. Barbecue

思路:若一开始就是回文串,那就后手赢;若一开始不是回文串,如果这子串不管是掐头还是去尾都是回文串的话,这个子串的情况类似于,ab,abab,ababab,这说明终止态的子串长度一定是偶数,因此输赢只和起始串长度 的奇偶性有关。

        但又因为n = 1e6 , q = 1e6 ,使用一般方法判断是否是回文的时间复杂度是O(n*q),这必然会超时,用字符串哈希判断是否是回文的时间复杂度是O(1),所以我们要用字符串哈希来降低判断是否是回文的时间复杂度。

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
typedef unsigned long long ULL ;
const int maxn = 1e6 + 10 ;
const int inf = 0x3f3f3f3f ;
const int base = 131 ;
char s[maxn] ;
//h是字符串正序hash值,h1是字符串逆序hash值
ULL p[maxn] , h[maxn] , h1[maxn] ;
int n , m ; 
ULL get(int l , int r){
    return h[r] - h[l-1] * p[r-l+1] ;
}
ULL get1(int l , int r){//求逆序哈希值 
	//因为是从n开始的第l-1个,和第r个 
    return h1[n-l+1] - h1[n-r] * p[r-l+1] ;
}
void deal(){
	scanf("%d %d %s" , &n , &m , s+1) ;
	p[0] = 1 ;
    for(int i = 1 ; i <= n ; i++){
        h[i] = h[i-1] * base + s[i] - 'a' + 1 ;
        h1[i] = h1[i-1] * base + s[n-i+1] - 'a' + 1 ;
        p[i] = p[i-1] * base ;
    }
	for(int i = 0 ; i < m ; i++){
		int l , r ; scanf("%d %d" , &l , &r) ;
		if(get(l , r) == get1(l , r) || ((r-l) & 1)){
			printf("Budada\n") ;
		}else{
			printf("Putata\n") ;
		}
	}
}
int main(){
	deal() ;
	return 0 ;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值