转自一位大佬:http://blog.csdn.net/wyxeainn/article/details/79588812
题目:
链接:https://www.nowcoder.com/acm/contest/70/C
来源:牛客网
题目描述
定义一个数字为幸运数字当且仅当它的所有数位都是4或者7。
比如说,47、744、4都是幸运数字而5、17、467都不是。
假设现在有一个数字d,现在想在d上重复k次操作。
假设d有n位,用d1,d2,…,dn表示。
对于每次操作,我们想要找到最小的x (x < n),使得dx=4并且dx+1=7。
如果x为奇数,那么我们把dx和dx+1都变成4;
否则,如果x为偶数,我们把dx和dx+1都变成7;
如果不存在x,那么我们不做任何修改。
现在请问k次操作以后,d会变成什么样子。
输入描述:
第一行两个整数n,k表示d的长度和操作次数。
第二行一个数表示d。数据保证不存在前导零。
1 <= n <= 100,000
0 <= k <= 1000,000,000
输出描述:
一个数字表示答案。
示例1
输入
7 4
4727447
输出
4427477
示例2
输入
4 2
4478
输出
4478
解题思路:题目K很大,一次次的变换,对于题目给出的1秒时间显然是
不可能过的。则根据题目分析如下。
1.最早出现47的地方,如果47后面有7,则此时出现序列477,如果4是第
奇数个字符,则一次变换后,序列为447,再次出现47,4是第偶数个字符,
变换后变成477。由此可知,出现477(且其里面的47是串里面最左侧的47),
对于剩余变换次数,如果是奇数,最终中间位为4,否则不变,遇到这种情况
不论还有多少次变换,只要确定变换次数的奇偶即可确定答案。
2.最早出现47的地方,如果47前面有4,则此时出现序列447,如果47中的4
是第偶数位字符,则变换一次,序列变成477,则再次变换一次,序列变成447.
可以发现,出现447(且其里面的47是串里面最左侧的47),对于剩余变换次数,
是奇数次,则中间的4最终为7,否则不变。遇到这种情况不论还有多少次变换,
只要确定变换次数的奇偶即可确定答案。
3.不是1,2两种情况,只是单纯找到了47,如果4是第奇数个字符,则47 -> 44.
下一次考虑47就要从后一个4开始检测了。
4.如果4是第偶数个字符,则47->77,则检测位置需要从4左侧的位置开始。
5.当串中没有47的时候,无论还剩余多少次变换都是无用的,应立即结束。
代码如下:
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
int n,k,temp;
char str[1000000];
int main() {
while(~scanf("%d%d",&n,&k)) {
scanf("%s",str);
//变换0次,直接输出。
if(k == 0) {
puts(str);
}
else {
for(int i = 0; i < n-1; i++) {
//遇到47组合。
if(str[i]=='4' && str[i+1]=='7') {
//遇到477组合
if(i+2<n && str[i+2]=='7') {
temp = i+1;
//4是第奇数个字符
if(temp%2==1) {
if(k%2==1) {
str[i+1] = '4';
}
k = 0;
}
}
if(!k) break;
//遇到447的组合。
if(i-1>=0 && str[i-1]=='4') {
temp = i+1;
//中间的4是第偶数个字符
if(temp%2==0) {
if(k%2) {
str[i] = '7';
}
k = 0;
}
}
if(!k) break;
temp = i+1;
//是第奇数个字符。
if(temp%2) {
str[i+1] = '4';
k--; //剩余变换次数-1
}
else {
str[i] = '7';
k--;
i = i-2;
/*i=i-2是因为,下次循环位置要从i-1开始,
由于for循环中i会自增,所有让i减去2,再
自增1,即下次循环从i-1开始。*/
}
if(!k) break;
}
}
puts(str);
}
}
return 0;
}