1. 程式人生 > >Codeforces Round #493 比賽總結

Codeforces Round #493 比賽總結

總述

作為一個新手,這是本人第一次認真打cf(上次打的時候電腦沒電關機了,這次電腦居然藍屏了一次,實在是傷不起呀),感觸也頗多,這裡進行一個總結吧。比賽連結http://codeforces.com/contest/998

998A.  Balloons

是一道大水題,只要根據n是1,是2或大於2分類討論,大於2時輸出最小數。可是當時想多了,題目理解錯了,WA了3次,到最後才發現真相,只得了150分。以後還是要提高姿勢水平呀,提高思考速度與手速。

#include<bits/stdc++.h>
#define REP(i,n) for(int i=0;i<n;++i)
using namespace std;
int a[15];
int main()
{
	int n;scanf("%d",&n);
	REP(i,n) scanf("%d",a+i);
	if(n<2) puts("-1");
	else if(n==2) {if(a[0]==a[1]) puts("-1");else puts("1\n1");}
	else{puts("1");int minn=0;
		REP(i,n) minn=(a[i]<a[minn])?i:minn;
		printf("%d\n",minn+1);
	}
	return 0;
}

998B. Cutting

水題,找到可以開刀的地方,儲存開刀花費,排序後貪心即可。

#include<bits/stdc++.h>
#define REP(i,n) for(int i=0;i<n;++i)
#define ms0(s) memset(s,0,sizeof(s))
#define abs(x) (((x)>0)?(x):-(x))
using namespace std;
int a[105],ok;
int cuts[105],cnt;
int main()
{
	int n,b;scanf("%d%d",&n,&b);ok=0;cnt=0;
	REP(i,n) {
		scanf("%d",a+i);
		ok+=(a[i]&1)?1:-1;
		if(ok==0&&i!=n-1) cuts[cnt++]=i;
	}
	REP(i,cnt) 
		cuts[i]=abs(a[cuts[i]]-a[cuts[i]+1]);
	sort(cuts,cuts+cnt);int cost=0;int i;
	for( i=0;cost<b&&i<n;i++)cost+=cuts[i];if(cost>b)i--;
	printf("%d\n",i);
	return 0;
}

998C. Convert to Ones

這道題需要稍微想一想,我們應當數一數整個串中有多少個互相分離的0部分(如001101有2個0部分),為了使效率最優,兩種操作最優方案如下:反轉操作把兩個0部分合為一體,使得0部分數量減少1;取反操作把一個0部分全部變為1,即消滅一個0部分。一次操作都能使0部分減少1,由此,把原有的k個0部分全部消滅需要進行k次操作。至少要1次取反,至多要k次。根據條件給出的價格,總開支是關於取反次數的線性函式,如果取反價格高,那就反轉k-1次,取反1次;如果反轉價格高,那就取反k次。

#include<bits/stdc++.h>
#define REP(i,n) for(int i=0;i<n;++i)
#define ms0(s) memset(s,0,sizeof(s))
using namespace std;
typedef long long ll;
int zero[300005],cnt;ll cost;
int main()
{
	int n,x,y;bitset<300005> b;
	scanf("%d%d%d",&n,&x,&y);cnt=0;
	bool one=1;
	REP(i,n){
		b[i]=(getchar()=='1');
		if(b[i]==0){if(one)cnt++,one=0;zero[cnt]++;}
		else one=1;
	}
	if(!cnt&&one) {puts("0");return 0;}
	cost=(ll)0;
	if(y<=x) cost=(ll)y*(ll)(cnt);
	else cost=(ll)y+(ll)x*(ll)(cnt-1);
	printf("%I64d\n",cost);
	return 0;
}

998D. Roman Digits

這是一道數學題,當時看了之後感覺要湊等效表達方式,但沒湊出來,就沒做出來。第二天仔細思考後發現,由於長度固定,實際上把{1,5,10,50}可以完全等效為{0,4,9,49},這一步讓拼湊大大簡化。可以證明,只要在一個數的表示中找不到4和9的個數為(0,9),(9,0),(1,5)的組,這個表示就是唯一的。(注:第一個可以將9個4換成4個9與5個0,第二個可以將9個9換成1個49與8個4,第三個可以把1個4,5個9換為1個49與5個0,這樣我們就找到了同一個數的不同表達方式)因此我們列舉剩下的組合,根據4和9用掉的數位個數分類相加,最後得到49n-247的表示式。但是對於n<12,有一些長度是達不到的,如n為4時就無法出現9個4的情況,要把這些多減去的情況加上,最後按n與12的大小關係分類討論進行輸出。(事實上直接打表找規律也是可以的,可惜當時沒想到)程式碼非常簡潔:

#include<bits/stdc++.h>
int a[]={0,4,10,20,35,56,83,116,155,198,244,292};
using namespace std;
typedef long long ll;
int main()
{
	int n;scanf("%d",&n);
	if(n<=11) printf("%d\n",a[n]);
	else printf("%I64d\n",(ll)49*(ll)n-(ll)247);
	return 0;
}

998E. Sky Full of Stars

這是一道較為困難的組合數學題,用容斥原理做,詳情參照官方題解。

總結

這次比賽結果rank1300+,rating+=24。

總的來說要改進的是以下幾個方面吧:

1. 問題想清楚了再程式設計,不要心急,像第一題WA3次就是沒想清楚的體現

2.提高編碼速度,提高調適能力。做了3道題的人最高排名是400左右,可是我罰時太高了,只排到1300.

3.後半場冷靜思考,注意找規律。像D題如果仔細想是可以做出來的,即使打表找規律也是有時間的,可惜當時有些怠惰了。

UPD:增加了題目程式碼