zoukankan      html  css  js  c++  java
  • [HEOI2015]定价 (贪心)

    分类讨论大法好!

    $ solution: $

    先说一下我对这个题目的态度:

    首先这一题是贪心,这个十分明显,看了一眼其他题解都是十分优秀的贪心,可是大家都没有想过吗:你们贪心都是在区间 $ [l,r] $ 上枚举的贪心,虽然每一次可以直接加上 10 的阶乘,但你们毕竟是用的 $ int $ , $ long long $  啊!。这一题得正解复杂度是 $ log_{10}(n) $ 的,不得不说题目的数据范围给的太小了只有 $ 10^9 $ ,如果按照复杂度,数据范围甚至可以到 $ 10^{10000000} $ 级别,这个时候你们难道还能在区间 $ [l,r] $ 上枚举吗?(高精怕都要超时!)

    所以虽然分类讨论十分麻烦,甚至代码很长,但它才应该是真正意义上的正解啊!(当然,考场见机行事)

    好的,不做“推销”了,我们进入正文。

    首先这一题,我们可以用字符串的方式读入两个端点值。然后如果我们仔细读题,就可以发现一些贪心方案

    1. 我们要让最终的价格数的高位上不是0的数尽可能的少!(当然,要在末尾全是0的基础上)
    2. 只有当不是0的数确定下来,我们再来判断最后一个不是0的数能否为5!
    3. 如果最后一个不是0的数不能为5,我们就要让最后一个不是0的数尽可能的小!
    4. 让最终得到的价格数尽可能的小!

    开始讨论之前先让你们有个思维准备:先看看下面代码有多少个 $ continue $ ,我们大概就要讲多少种情况。首先我们准备一个快写函数:将字符串 $ s $ 前 $ j-1 $ 位输出,然后将第 $ j $ 为换成字符 $ k $ ,再输出 $ n $ 个0

    然后为了涵盖多种情况,我们发现如果两个数的长度不一样,是很难讨论的。于是我们分三种情况:(两个数长度差了2位或以上)(两个数的长度差为1)(两个数长度相同)

    两个数长度差了2位或以上:(这个想一下,我们发现只有两种情况

    1. 如果较小的数的最高位比5小,就换成5输出(要特判5,50,500,5000......)
    2. 否则将较小的数的最高位换成5,再乘上10输出。

    两个数的长度差为1:(比上面要多一种情况)

    1. 如果较小的数的最高位比5小,就换成5输出(要特判5,50,500,5000......)
    2. 如果较大的数的最高位大于等于5,将较大的数的最高位换成5,输出。
    3. 将较小的的数的最高位上的数加1,然后全接0.(要特判如10,60,300等(高位不用加1))

    两个数长度相同:这个我们仔细想一下就会发现如果这两个数的高位相同,那么这些相同的高位可以直接输出了,所以我们放个循环 $ O(n) $ 找到不同的那一位,然后我们发现这一位后面的数可以忽略了(一定会被填成0的,因为贪心第一点:要让最终的价格数的高位上不是0的数尽可能的少)而针对这一位能否填成5,我们又有四中情况:

    1. 这两个数完全相同,这个直接输出
    2. 较小的数的这一位小于5,较大的数的这一位大于5,将这一位改成5输出(不需要特判5,50...这个归到下一类)
    3. 较小的数这一位后面全是0,直接输出
    4. 较小的数这一位后面不全是0,将这一位+1,然后输出。
    平心而论:这一题情况并不算多(详见猪国杀)

    对了,我们上文有提到一些需要特判的东西,这个只需要,在开始时用一个变量 $ f $ 来记录较小的数从那一位开始之后全是0即可!

    $ code: $

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define rg register int
    
    using namespace std;
    
    int t,a,b,f;
    char l[11];
    char r[11];
    
    inline void qw(char s[],int j,char k,int n){//有这个函数输出就方便多了
    	for(rg i=0;i<j;++i)putchar(s[i]);
    	k>'9'?printf("10"):putchar(k);
    	for(rg i=1;i<=n;++i)putchar('0');
    	puts("");
    }
    
    int main(){ cin>>t;
        //freopen("Price.in","r",stdin);
        //freopen("Price.out","w",stdout);
        while(t--){
            cin>>l>>r;
    		f=a=strlen(l)-1;
    		b=strlen(r)-1;
    		while(l[f]=='0')--f;//记录从那一位开始后面全是0
    		if(b-a>1){//差一位以上
    			if(l[0]<'5'||(l[0]=='5'&&f==0)){qw(l,0,'5',a);continue;}
    			qw(l,0,'5',a+1);continue;
    		}if(b-a>0){//差一位
    			if(l[0]<'5'||(l[0]=='5'&&f==0)){qw(l,0,'5',a);continue;}
    			if(r[0]>='5'){qw(l,0,'5',b);continue;}
    			if(f==0){qw(l,0,l[0],a);continue;}
    			qw(l,0,l[0]+1,a);continue;
    		}int i=0;while(l[i]==r[i]&&i<=a)++i;//找到不同的哪一位
    		if(i>a||f<i){qw(l,a,l[a],0);continue;}
    		if(l[i]<'5'&&r[i]>='5'){qw(l,i,'5',a-i);continue;}
    		if(f==i){qw(l,i,l[i],a-i);continue;}
    		qw(l,i,l[i]+1,a-i);
        }
        return 0;
    }
    
    

    情况都是按上文顺序写的,但本人还是很菜可能思虑不周,欢迎大家来hack(hack成功了麻烦提醒一下,O(∩_∩)O谢谢)

  • 相关阅读:
    一题多解(六)—— 一个数二进制形式 1 的个数
    心算技巧
    心算技巧
    位运算应用及其注意事项
    位运算应用及其注意事项
    辨异 —— 不同的编程语言(编译型语言、解释型语言、动态语言、静态语言)
    C#POP3协议实现SSL验证登陆GMAIL
    PB学习笔记(一)
    24点计算 --- 庞果
    JAVA网站高并发解决方案
  • 原文地址:https://www.cnblogs.com/812-xiao-wen/p/10333583.html
Copyright © 2011-2022 走看看