题目链接:625D - Finals in arithmetic
这道题是Special Judge。开始是aynuzzh让我去做的。题目大意是定义a翻转后为ar,例如当a=123时,ar=321。给出一个数n(1≤n≤10100 000),求a满足a+ar=n。答案可能有很多,输出其中的一个即可。
我们先来看,假如有一个数每一位为a,b,c,d,那么翻转之后就是d,c,b,a,相加的结果是a+d,b+c,c+b,d+a,是一个回文数。那么我们就要将n分解成一个回文的数列来求a。我们知道a的每一位必定为0~9之一,那么分解出来的回文数列的每一项就为0+0~9+9即0~18之一。
我们用处理高精度的方式处理n。先来处理n的最高位,如果n的最高位与最低位不相同,我们就将n的最高位退位再匹配是否相等。如果无法匹配,那么无解。
我们设立l,r两个指针从最高位与最低位向中间扫描。对于每个应当匹配的l,r两个位置,如果它们相等,那么不用处理。如果不相等,那么如果l>=10(也就是前一位退过位)且r<10(也就是前一位没有退位)我们就把r的前一位退位使得l,r指向的位置都满足>=10的条件(前一位退过位)。接下来,如果l-r=1,我们就令l指向的位置退位,那么l,r就匹配了。如果操作之后仍然无法匹配,那么无解。
分解完成后,我们需要求出答案a。首先,回文数列每一项是x+y(0≤x,y≤9)的形式,我们就把匹配的两项一项取x,一项取y。如果有一项是自身与自身匹配,那么必定这一项是x+x的形式。我们需要判断这一位是否是偶数,只有偶数才能符合2x的条件。如果是奇数,则无解。当分解完成后,我们要检验有没有不符合条件(也就是大于9或者小于0)的值,如果有则无解。最后,将数列每一项合并成a即可出一组解。我们将数列扫了两遍,所以时间复杂度为O(2n)。还可以优化吗?可以。在第一遍扫描的过程中我们也可以同时将第二遍扫描的任务完成,求出答案a。故最后的时间复杂度仅为O(n)。
#:15927417
Author:_Snakes_
Problem:625D
Lang:GNU C++11
Verdict:Accepted
Time:31 ms
Memory:0 KB
Sent:2016-02-10 13:33:00
Judged:2016-02-10 13:33:01
1 #include <cstdio> 2 using namespace std; 3 int main() 4 { 5 char s[100005]; 6 int n,l,r; 7 while ((scanf("%c",&s[++n])==1)&&(s[n]>=‘0‘)&&(s[n]<=‘9‘)) 8 s[n]-=‘0‘; 9 l=1; 10 r=--n; 11 if (s[l]!=s[r]) 12 { 13 s[l]--; 14 s[l+1]+=10; 15 if (s[l]==0) 16 l++; 17 } 18 while (l<=r) 19 { 20 if (s[l]!=s[r]) 21 { 22 if ((s[l]-s[r]>=10)&&(s[r]<10)) 23 { 24 s[r-1]--; 25 s[r]+=10; 26 } 27 if (s[l]-s[r]==1) 28 { 29 s[l]--; 30 s[l+1]+=10; 31 } 32 } 33 if (s[l]!=s[r]) 34 break; 35 if (l!=r) 36 { 37 s[l]=s[l]-(s[r]>>1); 38 s[r]>>=1; 39 } 40 else 41 if (((s[l]>>1)<<1)==s[l]) 42 s[l]>>=1; 43 else 44 break; 45 if (s[l]>9||s[l]<0||s[r]>9||s[r]<0) 46 break; 47 l++; 48 r--; 49 } 50 if (l<=r) 51 { 52 printf("0"); 53 return 0; 54 } 55 l=1; 56 if (s[l]==0) 57 l++; 58 while (l<=n) 59 { 60 printf("%d",s[l]); 61 l++; 62 } 63 return 0; 64 }