19th浙大校賽題解報告

睡過頭,下午匆匆忙忙趕到機房已經14點了,發現還好比賽沒有開始。
定下心和隊友吹吹水等待比賽開始。

開始英語廢材淡定的等待隊友讀題,在榜單上陸續有隊伍AC後我們確定先讀E題。

E.Potion

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

隊友讀完一看發現就是簡單模擬題,從最高層一直往下模擬就行,遂1Y。
code

#include<iostream>
#include<cstdio>
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<iostream>
#include<cstdio>
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<iostream>
#include<cstdio>
#include<queue>
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<iostream>
#include<cstdio>
#include<algorithm>
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!!=24=10(2)+100(2)4!!=2*4=10_{(2)}+100_{(2)}結果爲3.
6!!=246=10(2)+100(2)+110(2)6!!=2*4*6=10_{(2)}+100_{(2)}+110_{(2)}結果爲4
這時我們發現只要知道e!!e!!運算過程中每個數末尾0的個數和就是我們要的結果。
然後進一步找規律又發現了e=10=1010(2)e=10=1010_{(2)}的結果爲(231)+(211)(2^3-1)+(2^1-1)
然後就蜜汁自信用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<iostream>
#include<cstdio>
#include<cstring>
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的問題,無奈公主的位置一直變化不知道怎麼確定根節點,故放棄,開啓和隊友吹水模式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章