题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4029
题意概述:
对于一个数字的荒谬程度定义如下:删除其所有的后缀0,然后得到的数字长度为a,如果最后一个数字是5,荒谬程度为2*a-1,否则荒谬程度为2*a
现给出一些区间[L,R],询问区间内荒谬程度最小的价格。如果有多个,给出最低的那个。
T<=100,1<=L,R<=10^9
分析:
本来以为找到了一个数位dp的题结果发现随意分析一下性质就成了个贪心。。。。
首先可以发现最后一位是非0的情况都可以O(1)求解,需要注意的只有是0的情况,而且一定要是连续的0才有去枚举的意义。从后往前做(好想一点),每次把最后一位如果小于5且不为0就变成5,然后更新一次答案,如果不为0就再变成0,然后更新一次答案。(不管变不变答案是要更新的)
这个做法的正确性的话贪贪就有了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 using namespace std; 13 14 int T,L,R; 15 16 int calc(int x) 17 { 18 while(x%10==0) x/=10; 19 int len=0,d=x%10==5?-1:0; 20 while(x) x/=10,len++; 21 return len*2+d; 22 } 23 void work() 24 { 25 int ans=L,tmp=L,add=1,MIN=calc(L); 26 for(int i=0;i<=8&&tmp<=R;i++) { 27 if(0<tmp/add%10&&tmp/add%10<5) tmp=(tmp/add-tmp/add%10+5)*add; 28 if(tmp<=R&&calc(tmp)<MIN) ans=tmp,MIN=calc(tmp); 29 if(0<tmp/add%10) tmp=(tmp/add-tmp/add%10+10)*add; 30 if(tmp<=R&&calc(tmp)<MIN) ans=tmp,MIN=calc(tmp); 31 add*=10; 32 } 33 printf("%d ",ans); 34 } 35 int main() 36 { 37 freopen("test.in","r",stdin); 38 freopen("test.out","w",stdout); 39 scanf("%d",&T); 40 for(int i=1;i<=T;i++) { 41 scanf("%d%d",&L,&R); 42 work(); 43 } 44 return 0; 45 }