浙江大学第十九届“图森未来杯”程序设计竞赛游记——杨子曰

浙江大学第十九届“图森未来杯”程序设计竞赛游记——杨子曰

第二次参加图森杯了,去年A了三题,今年有六题,不错不错……


比赛题目一览:
A:Thanks, TuSimple!
B: Even Number Theory
C:Robot Cleaner I
D:Robot Cleaner II
E:Potion
F:Strange Function
G:Postman
H: Rescue the Princess
I:Defense Plan
J:Extended Twin Composite Number


比赛一开始,就有人切掉了J题,噢,一定是大水题啊!
J题讲的是给你一个整数n,让你随便找一组整数解x,y,使得x+n=y,而且x和y都是合数

沉默……

“哦,这岂不是很简单吗!如果n是偶数,那就随便找两个差4的偶数不就好了,如果n是奇数,那就找个9和9+n就行了,9+n一定是偶数,如此之简单”

AC!

#include
using namespace std;

int main(){
	int cas;
	scanf("%d",&cas);
	while(cas--){
		long long n;
		scanf("%lld",&n);
		if (n%2==0) printf("4 %lld\n",4+n);
		else printf("9 %lld\n",9+n); 
	}
	return 0;
} 

看下ranklist,发现可以做E题
嗯,这题什么意思?
什么,降级?魔药?……(←论英语的重要性)
……
在百般挣扎后终于看懂了题目,按等级给你一堆材料的需求量,再按等级给出你有多少材料,你所拥有的材料是可以降级的,将级没有限制,降几级,降几次都可以,然后问你材料够不够

呵呵,那不就是一道水题吗?从后往前扫,多出来的能降级就降级,一单不够了就条出
WA!!!
哦哦哦,long long

AC!!!

#include
using namespace std;

const int maxn=105;

long long a[maxn],b[maxn];

int main(){
	int cas;
	scanf("%d",&cas);
	while(cas--){
		int n,flag=0;
		scanf("%d",&n);
		for (int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
		}
		for (int i=1;i<=n;i++){
			scanf("%lld",&b[i]);
		}
		for (int i=n;i>=1;i--){
			if (a[i]>b[i]){
				printf("No\n");
				flag=1;
				break;
			}
			else{
				b[i-1]+=b[i]-a[i];
			}
		}
		if (!flag) printf("Yes\n");
	}
	return 0;
} 

接着就是G题了:
题目意思很简单:就是再一个数轴上,原点是邮局,每次到邮局可以拿不超过k封信,给出需要送信的坐标,问最少要跑多远

好吧,又是水题,到了原点我们的信就可以加满了,So,正负半轴我们完全可以分开讨论

显然每一次我送的k封信一定是连续的,那我们就把这些点每k个分成一段,那么每一段的代价都是从远点到这一段最远那个点的距离*2,由于最后一次只去无回(←听上去怪怪的),So,我们把到原点距离最远的减掉一个(正负半轴只能减一个),完事

#include
using namespace std;

int n,k;
vector<int> a,b; 

int main(){
	int cas;
	scanf("%d",&cas);
	while(cas--){
		long long ans=0;
		a.clear();
		b.clear();
		scanf("%d%d",&n,&k);
		for (int i=1;i<=n;i++){
			int tmp;
			scanf("%d",&tmp);
			if (tmp==0) continue;
			if (tmp>0) a.push_back(tmp);
			else b.push_back(-tmp);
		}
		sort(a.begin(),a.end());
		sort(b.begin(),b.end());
		for (int i=a.size()-1;i>=0;i-=k){
			ans+=1ll*a[i];
		}
		for (int i=b.size()-1;i>=0;i-=k){
			ans+=1ll*b[i];
		}
		ans*=2;
		ans-=max(a[a.size()-1],b[b.size()-1]);
		printf("%lld\n",ans);
	}
	return 0;
}

A题,这题面也忒长了吧!!
真正有用的好像只有后面一段:
现在要跳舞,给出男生身高,女生身高,有些男女搭配跳舞,有的人只想和比自己高的人跳,有的人只想和比自己矮的人跳,问:最多可以匹配出多少对?

哦?怕不是一道二分图匹配?
显然不是,这道题中有4种人:

  1. 想要和比自己高的人跳舞的男生
  2. 想要和比自己矮的人跳舞的男生
  3. 想要和比自己高的人跳舞的女生
  4. 想要和比自己矮的人跳舞的女生

显然只能1 4搭配,2 3搭配,怎样搭配捏?排序后两个指针扫一下不久行了吗?
AC

#include
using namespace std;

const int maxn=100005;

int n,m;
vector<int> mt,ms,wt,ls;
int a[maxn],b[maxn];

int main(){
	int cas;
	scanf("%d",&cas);
	while(cas--){
		int ans=0;
		mt.clear();
		ms.clear();
		wt.clear();
		ls.clear();
		scanf("%d%d",&n,&m);
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		for (int i=1;i<=m;i++) scanf("%d",&b[i]);
		for (int i=1;i<=n;i++){
			int k;
			scanf("%d",&k);
			if (k==1)  mt.push_back(a[i]);
			else ms.push_back(a[i]);
		}
		for (int i=1;i<=m;i++){
			int k;
			scanf("%d",&k);
			if (k==1) wt.push_back(b[i]);
			else ls.push_back(b[i]);
		}
		sort(mt.begin(),mt.end());
		sort(ms.begin(),ms.end());
		sort(wt.begin(),wt.end());
		sort(ls.begin(),ls.end());
		int i=0,j=0;
		while(i<ls.size() && j<mt.size()){
			if (ls[i]>mt[j]) ans++,i++,j++;
			else i++;
		}
		i=0,j=0;
		while(i<ms.size() && j<wt.size()){
			if (ms[i]>wt[j]) ans++,i++,j++;
			else i++;
		}
		printf("%d\n",ans);
	}
	return 0;
}

然后我们就入坑了B题:
好复杂的题面:
它定义了一坨名词:
e-prime:不能拆成两个偶数的数
e-prime分解:把一个数拆分成一堆e-prime乘积的形式
e-阶乘:e!!:就是用偶数做阶乘
给你一个n,问你n!!最多可以被分解成多少个e-prime

好难啊!左想想,右想想,A出这道题的人越来越多了!!!
忒难了吧!

哦,等等等,这个even是啥意思,偶数!!!!!!!!!!!!!!!
e-prime只能是偶数,呃……

那么只要有一个2我们就可以分解出一个e-prime,那就要看由于n!!的每一项都有一个2,那我们就是要看(n/2)!里有多少个2就行了,简单,还要高精度!!!

(不知道比赛结束后,我打了一遍就tle了,大佬发现错误可以在评论中回复,谢谢)
2019.5.3upd:我居然过了,结构体里面的数组开大了!
tle代码:

#include
using namespace std;

char ch[2005];

struct BIG_NUM{
	int a[2005],len;
	void insert(char *s){
		len=strlen(s); 
		for (int i=0; i<len; i++) 
			a[len-i]=s[i]-'0';
	}
	void clear(){
		len=0;
		memset(a,0,sizeof(a));
	} 
}n;

BIG_NUM operator + (BIG_NUM a, BIG_NUM b) {
	BIG_NUM c;
	c.clear();
	c.len=max(a.len,b.len)+1; 
	for (int i=1;i<=c.len;i++){
		c.a[i]=a.a[i]+b.a[i]+c.a[i];
		c.a[i+1]=c.a[i]/10;
		c.a[i]=c.a[i]%10;
	}
	while(c.a[c.len]==0) c.len--;
	return c;
}

BIG_NUM operator / (BIG_NUM a, int b) {
	BIG_NUM c;
	c.clear();
	c.len=a.len;
	int x=0;
	for (int i=a.len;i>=1;i--){
		int tmp=(a.a[i]+x)/b;
		x=(a.a[i]+x)%b*10;
		c.a[i]=tmp;
	}
	while(c.a[c.len]==0) c.len--;
	return c;
}


int main(){
	int cas;
	scanf("%d",&cas);
	while(cas--){
		BIG_NUM ans;
		ans.clear();
		scanf("%s",ch);
		n.insert(ch);
		if (n.len==1 && n.a[1]==1) {
			printf("1\n");
			continue;
		}
		n=n/2;
		ans=n;
		while(n.len>0){
			n=n/2;
			ans=ans+n;
		}
		for (int i=ans.len;i>=1;i--){
			printf("%d",ans.a[i]);
		}
		puts("");
	}
	return 0;
}

啊,封榜了

C题走起

题面太麻烦了,自行体会:C题

“呃,这一定会出循环呀!”
“那怎么样会出循环捏?”
“……”
“管他呢,直接循环5000000次好了”
T了
“那试试2000000次”
A了

A得好突然!

#include
using namespace std;

char ch[250];
int n,m,aa,bb,a[2005][2005];
long long k;

int calc(int i,int j){
	return 81*a[i][j]+27*a[i-1][j]+9*a[i+1][j]+3*a[i][j-1]+a[i][j+1];
}

int main(){
	int cas;
	scanf("%d",&cas);
	while(cas--){
		int ans=0;
		scanf("%d%d%d%d%lld",&n,&m,&aa,&bb,&k);
		scanf("%s",ch);
		for (int i=1;i<=n;i++){
			for (int j=1;j<=m;j++){
				scanf("%1d",&a[i][j]);
			}	
		}
		k=min(k,1ll*2000000);
		int x=aa,y=bb;
		char tmp;
		for (int i=1;i<=k;i++){
			tmp=ch[calc(x,y)];
			if (tmp=='U'){if (a[x-1][y]!=1) x--;}
			else if (tmp=='D'){if (a[x+1][y]!=1) x++;}
			else if (tmp=='L'){if (a[x][y-1]!=1) y--;}
			else if (tmp=='R'){if (a[x][y+1]!=1) y++;}
			else if (tmp=='P'){if (a[x][y]==2) a[x][y]=0,ans++;};
		}
		printf("%d\n",ans);
	}
	return 0;
}

嗯,这题还有续集!
顺理成章地来到了D题,What,让你写个命令然后special judge!intereseting
推了半天,WA了29发,然后Game over!


A了6道题,我们还是尽力了,今年应该没有ACM了,下次加油!

与HG机房

你可能感兴趣的:(游记)