【题目描述】
众所周知,每当我们看见自己糟糕的成绩时,我们总希望以奇怪的方式将其四舍五入。
Efim同样如此。在晴朗的一天,Efim拿到了他的成绩X,他希望通过最多m次四舍五入使他的成绩最大化(每一次四舍五入舍掉的的位置任意,但只能在小数部分,不能在整数部分)。注意:m次可以不用完。
例如1.14四舍五入掉最后一位后为1.1。1.5四舍五入后为2。1.299四舍五入后为1.3。
【输入】
第一行两个整数n和m,n表示X的字符数。1<=n<=200000,1<=m<=1000000000。
第二行一个实数X,表示Efim的成绩。
【输出】
一个实数X,表示他的成绩的可能的最大值,Efim不希望他的成绩有后缀零。
【输入样例1】
6 1 10.245
【输出样例1】
10.25
【输入样例2】
6 2 10.245
【输出样例2】
10.3
【输入样例3】
3 100 9.2
【输出样例3】
9.2
【提醒】
这道题同学们应追求满分,而不是满足于70,8090分。
时间限制 : 1s
空间限制 : 256M
看着比赛的最后一句话,就知道肯定是一个细节很多的题(不然一般不会有70,80,90这三个这么接近的数字)
首先,肯定是在越前面四舍五入越好,因为比较数位是从前往后一位一位比较的。难道这道题就这样做完了?
不。如果是样例10.245这种情况,五入了还可以再次五入,那就不行了。同时还有出现9进位导致在此进位的情况。所以我们要不断地往前面找,如果又可以五入并且还有次数那就五入,如果有9可以进位那就进位。但是细节还是有点多的。首先五入只能在小数点后,同时进位时如果跨过了小数点那么要加在整数上,如果小数全部进完了那就要省略小数点。具体的细节还是看代码吧,细节真的很多。
#include<iostream> #include<cstdio> using namespace std; const int N=2e5+5; char s[N]; int n,m,f1,st; int main() { scanf("%d%d%s",&n,&m,s+1); s[0]='0'; for(int i=1;i<=n;i++) { if(f1&&s[i]>='5') { st=i; for(int j=i+1;j<=n;j++) s[j]=0; break; } if(s[i]=='.') f1=1; } if(!st) { cout<<(s+1)<<endl; return 0; } for(int i=st;i!=0;i--) { if(s[i]!='.') { if(s[i]=='9'+1) { s[i]='0'; if(s[i-1]!='.') s[i-1]++; else s[i-2]++; } if(s[i]>='5'&&m&&f1) { if(s[i-1]!='.') s[i-1]++; else s[i-2]++; m--,s[i]=0; } } else f1=0; } for(n=0;s[n+1];++n); if(s[n]=='.') s[n]=0; if(s[0]=='0') printf("%s",s+1); else printf("%s",s); return 0; }
可以比赛调对的人真的很强。