算法
贪心+无数有趣的细节
高能预警:本题细节较多,请仔细食用。
思路
从小数点往后搜,直到遇见第一个(geq 5)的数字,它就是我们要四舍五入的第一个。然后从它开始往回搜,只要(geq 5)就四舍五入。
正确性
小数点后位数靠前的数字越大,值越大,所以我们将第一个能“(5)入”的点“入”掉(因为这样才能使得“入”过去的(1)价值最大)。
那为什么往回搜的时候能入则入呢?
- 因为往回搜的数必然是小于(5)的,只有当前的数往前进了位才有可能(geq 5),所以我们只能给当前数进位(如果它可以)。
细节
- 整数位上不能四舍五入(但可以进位)!
- 小数位与整数位的进位要分开处理!
- 可能出现一个也不能进的情况!
- 整数的最高位有可能进(1)! (如:(99.459))
- 记得判断没有小数点的情况!
大概就这么多了……
参考代码
/*
* @Author: When_C
* @Date: 2020-11-19 19:29:11
* @Last Modified by: When_C
* @Last Modified time: 2020-11-19 19:49:45
*/
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 2e5 + 10;
int n,t,a[maxn],top;
char c[maxn];
int main(){
scanf("%d%d%s", &n, &t, c + 1);
int loc,pos = -1;
for(int i = 1; i <= n; ++ i){
if(c[i] >= '0' && c[i] <= '9') a[++top] = c[i] - '0';
else loc = top + 1;
}
for(int i = loc; i <= top; ++ i)
if(a[i] >= 5){pos = i; break;}
if(pos > 0){
int pre = 1; pos -= 1; t -= 1;
for(int i = pos; i >= 1; -- i){
if(!pre && (!t || i < loc)) break;
a[i] += pre; pre = 0;
if(a[i] > 10) pre = 1, a[i] %= 10;
if(a[i] == 10){
pre = 1; a[i] %= 10;
if(i >= loc) pos -= 1;
}
if(a[i] >= 5 && t && i >= loc) pre += 1, pos -= 1, t--;
}
if(pre) a[0] = 1;
}
if(a[0]) printf("%d", a[0]);
for(int i = 1; i <= pos; ++ i){
printf("%d", a[i]);
if(i == loc - 1 && i != pos) printf(".");
}
if(pos < 0) printf("%s", c + 1);
return 0;
}