总述
作为一个新手,这是本人第一次认真打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:增加了题目代码