19th浙大校赛题解报告

睡过头,下午匆匆忙忙赶到机房已经14点了,发现还好比赛没有开始。
定下心和队友吹吹水等待比赛开始。

开始英语废材淡定的等待队友读题,在榜单上陆续有队伍AC后我们确定先读E题。

E.Potion

http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5973

队友读完一看发现就是简单模拟题,从最高层一直往下模拟就行,遂1Y。
code

#include
#include
using namespace std;
const int maxn = 1e2+10;
long long a[maxn], b[maxn];
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		int n;
		scanf("%d", &n);
		for(int i = 0; i < n; i++){
			scanf("%lld", &a[i]);
		}
		for(int i = 0; i < n; i++){
			scanf("%lld", &b[i]);
		}
		bool flag = true;
		for(int i = n-1; i >= 0; i--){
			if(b[i]>=a[i] && i != 0){
				b[i-1] += b[i]-a[i];
			}
			else if(b[i]>=a[i]){
				continue;
			}
			else{
				flag = false;
			}
		}
		if(flag) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

J.Extended Twin Composite Number

http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5977

就在我光(gui)速(su)AC时队友已经把J题题意读懂了。
就是在构造两个合数(x, y)使得n+x=y。
这时我想到合数,那么2的倍数(除了2)的数一定就是合数。那只要将y构造成偶数就可以了。
这样只要处理当n为奇数和偶数两种情况就可以了。
当n为偶数,要使y为偶数,只要加上偶数4就可以了(2是素数)
当n为奇数,要使y为偶数,只要加上奇数9就可以了(其他小于9的奇数均为素数)
遂1Y

code

#include
#include
using namespace std;
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		long long n;
		scanf("%lld", &n);
		if(n&1) printf("%lld %lld\n", 9ll, 9+n);
		else printf("%lld %lld\n", 4ll, 4+n);
	}
	return 0;
}

顺利切下两题后看了下榜单,发现A题过的人数挺多的,所以我又自然而然开始划水等队友读题

A.Thanks, TuSimple!

http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5969
读完题意我傻逼想成二分图匹配,被队友B当头一棒说如果是二分图那建完图空间都不够用了。
重新思考了下和队友发现就还是一个简单的模拟问题。
考虑建一个从小到大排序的优先队列,分别将男生(匹配高),女生(匹配矮),男生(匹配矮),女生(匹配高)扔进各自队列。
1.最矮的想要匹配高的男生和最矮的想要匹配矮的女生身高对比,如果男生比女生高那该女生则无法匹配直接出队继续进行1,如果男生比女生矮则贡献+1,男生女生同时出队。直到某一队列中没有男生或者女生。
2.同1身份调换。

code

#include
#include
#include
using namespace std;
const int maxn = 1e5+10;
priority_queue<int,vector<int>, greater<int> > N0;
priority_queue<int,vector<int>, greater<int> > N1;
priority_queue<int,vector<int>, greater<int> > M0;
priority_queue<int,vector<int>, greater<int> > M1;
int w1[maxn], w2[maxn];
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		while(!N0.empty()) N0.pop();
		while(!N1.empty()) N1.pop();
		while(!M0.empty()) M0.pop();
		while(!M1.empty()) M1.pop();
		int n, m;
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i++){
			scanf("%d", &w1[i]);
		}
		for(int i = 1; i <= m; i++){
			scanf("%d", &w2[i]);
		}
		int x;
		for(int i = 1; i <= n; i++){
			scanf("%d", &x);
			if(x) N1.push(w1[i]);
			else N0.push(w1[i]);
		}
		for(int i = 1; i <= m; i++){
			scanf("%d", &x);
			if(x) M1.push(w2[i]);
			else M0.push(w2[i]);
		}
		int ans = 0;
		while(!N0.empty() && !M1.empty()){
			int x = N0.top(), y = M1.top();
			if(x > y){
				ans+=1;
				N0.pop();
				M1.pop();
			}
			else{
				N0.pop();
			}
		}
		while(!M0.empty() && !N1.empty()){
			int x = M0.top(), y = N1.top();
			if(x > y){
				ans+=1;
				M0.pop();
				N1.pop();
			}
			else{
				M0.pop();
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

确定好思路后我又继续写代码,队友去读G。
不久后1Y,同时队友B也把G题思路想到了,故让队友B码题,我旁边划水。
过程中我和另一位队友C讨论了B题,一头雾水,这边队友C也连续WA了两发(ZOJ上提交没有显示WA导致我们以为没有提交连续交了两发相同代码,可恶啊)。
我重新和队友B讨论了下G题的思路,感觉没有什么问题,就对这他的代码改了改,交了还是WA。
这时候我们已经排名–,开始慌的一匹。
过了许久我跟队友说可能是玄学,我重新写一份交一下,。。。。。“YES”,有点东西,和队友近乎一样的代码重写一遍就过了????

G.Postman

http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5975
G题思路分左右每次跑到最远处并且携带k封信之后返回,最后判断左右两边最远端点哪个大去掉哪个就是答案
code

#include
#include
#include
using namespace std;
const int maxn = 1e5+10;
long long w1[maxn], w2[maxn];
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		int n, m, n1, n2;
		long long ans = 0, t;
		n1 = n2 = 0;
		scanf("%d%d", &n, &m);
		for(int i = 0; i < n; i++){
			scanf("%lld", &t);
			if(t < 0) w2[n2++] = -t;
			else w1[n1++] = t;
		}
		sort(w1, w1+n1);
		sort(w2, w2+n2);
		for(int i = n1-1; i >= 0; i-=m) ans+=2*w1[i];
		for(int i = n2-1; i >= 0; i-=m) ans+=2*w2[i];
		if(w1[n1-1] > w2[n2-1]){
			ans-=w1[n1-1];
		}
		else{
			ans-=w2[n2-1];
		}
		printf("%lld\n", ans);
	}
	return 0;
}

B.Even Number Theory

http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5970
过完G题,又回到了B题。
发现 4 ! ! = 2 ∗ 4 = 1 0 ( 2 ) + 10 0 ( 2 ) 4!!=2*4=10_{(2)}+100_{(2)} 4!!=24=10(2)+100(2)结果为3.
6 ! ! = 2 ∗ 4 ∗ 6 = 1 0 ( 2 ) + 10 0 ( 2 ) + 11 0 ( 2 ) 6!!=2*4*6=10_{(2)}+100_{(2)}+110_{(2)} 6!!=246=10(2)+100(2)+110(2)结果为4
这时我们发现只要知道 e ! ! e!! e!!运算过程中每个数末尾0的个数和就是我们要的结果。
然后进一步找规律又发现了 e = 10 = 101 0 ( 2 ) e=10=1010_{(2)} e=10=1010(2)的结果为 ( 2 3 − 1 ) + ( 2 1 − 1 ) (2^3-1)+(2^1-1) (231)+(211)
然后就蜜汁自信用Py写了下(C处理大数比较麻烦,然后当时偷懒不想用JAVA的大数类写,就选择用Py。不过正式赛上没有Py,以后还是得注意下),遂1Y。

队友B简直规律大师NB!!!
code

T = (int)(input())
while T!=0:
	T-=1
	n = (int)(input())
	ans = 1
	cnt = 0
	while n!=0:
		if n %2 == 1:
			cnt+=ans-1
		ans*=2;
		n = n/2;
	print(cnt)

这时看了下排名好像在100+左右,总算是又滚回来了。
在队友们读C题时候我又开始我的划水之旅。
读完题,发现还是一个比较简单的模拟题。
很快我们就确定了思路。

C.Robot Cleaner I

http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5971
1e18的步数一定存在一个循环结,说明我们只要一直模拟到原来走到的位置那么就是一次循环,我们就可以直接输出结果。这样只要每次将走过的路进行标记就可以了。但题面存在一个问题,但捡起一个碎片时地图该位置会从’2’变成’0‘,这样地图就发生了改变,所以每次出现这种情况我们就需要重新刷新地图把原先标记取消。
确定好时间复杂度够之后我就码题,然后无比气愤的得到了今天的第一个WA(之前改队友题面的WA不算哈哈哈)检查下发现memset清空标记用的时间太长了,故直接改成两层for后返回"YES".
code

#include
#include
#include
using namespace std;
const int maxn = 2e3+10;
char s[maxn];
char map[maxn][maxn];
int dir[5][2] = {0, 0, -1, 0, 1, 0, 0, -1, 0, 1};
bool vis[maxn][maxn];
int pow(int x, int p){
	int ans = 1;
	while(p){
		if(p&1) ans = ans*x;
		x = x*x;
		p>>=1;
	}
	return ans;
}
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		int n, m, x, y, step;
		scanf("%d%d", &n, &m);
		for(int i = 0; i <= n; i++){
			for(int j = 0; j <= m; j++){
				vis[i][j] = false;
			}
		}
		scanf("%d%d%d", &x, &y, &step);
		scanf("%s", s);
		for(int i = 1; i <= n; i++){
			scanf("%s", map[i]+1);
		}
		int ans = 0;
		while(step--){
			if(vis[x][y]){
				break;
			}
			vis[x][y] = true;
			int k = 0;
			for(int i = 0, j = 4; i <= 4; i++, j--){
				int tx = x+dir[i][0], ty = y+dir[i][1];
				k+=(map[tx][ty]-'0')*pow(3, j);
			}
			if(s[k]=='U'){
				int tx = x+dir[1][0], ty = y+dir[1][1];
				if(map[tx][ty] != '1'){
					x = tx, y = ty;
				}
			}
			else if(s[k]=='D'){
				int tx = x+dir[2][0], ty = y+dir[2][1];
				if(map[tx][ty] != '1'){
					x = tx, y = ty;
				}
			}
			else if(s[k]=='L'){
				int tx = x+dir[3][0], ty = y+dir[3][1];
				if(map[tx][ty] != '1'){
					x = tx, y = ty;
				}
			}
			else if(s[k]=='R'){
				int tx = x+dir[4][0], ty = y+dir[4][1];
				if(map[tx][ty] != '1'){
					x = tx, y = ty;
				}
			}
			else if(s[k]=='P'){
				if(map[x][y]=='2'){
					map[x][y]='0';
					ans+=1;
					for(int i = 0; i <= n; i++){
						for(int j = 0; j <= m; j++){
							vis[i][j] = false;
						}
					}
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

最后剩下一点时间我们讨论了下H题,感觉想是一个缩点+LCA的问题,无奈公主的位置一直变化不知道怎么确定根节点,故放弃,开启和队友吹水模式。

你可能感兴趣的:(ACM)