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:增加了題目程式碼