SPOJ10649 Mirror Number(三进制回文)

来源:互联网 发布:网络电视最清楚的软件 编辑:程序博客网 时间:2024/06/15 16:45

/*

题目:Mirror Number

题目描述:

A number is called a Mirror number if on lateral inversion, it gives the same number i.e it looks the same in a mirror. For example 101 is a mirror number while 100 is not. 

Given two numbers a and b, find the number of mirror numbers in between them (inclusive of a and b).

大意:求区间[a,b]内有多少个mirror数,mirror数是左右对称的,如0,1,8,11,88,101,111,181,808,818,888等,而其他的包含有非0,1,8数位的回文数则不是;

Input

First line contains T, number of testcases <= 10^5.
Each testcase is described in a single line containing two numbers a and b.
0 <= a<=b <= 10^44

Output

For each test case print the number of mirror numbers between a and b in a single line.

 

解题思路:

写一个求F(0,n)区间的mirror数的个数函数,那么答案就是F(b)- F(a-1);

F函数的思路如下:

第一步找出小于等于n,且是回文的数m;

第二步找出小于等于m,且只包含0,1,8,的数x;

第三步把0,1,8看成是三进制,类似于求区间回文数(只不过回文数里面可用的数字有10个,所以是10进制),统计奇数个位和偶数个位上的个数;

 

最后相加就是答案;

 

代码:

*/

 

 

#include<stdio.h>#include<string.h>#define LL long longint ternary[10],vis[3]={8,1,0};void getCloseNum(char *num){int i,j,tag;for(i=1;i<=num[0];i++){tag=-1;for(j=0;j<3;j++){if(num[i]==vis[j])break;if(tag<0&&num[i]>vis[j]) tag=j;}if(j>=3){num[i++]=vis[tag];for(;i<=num[0];i++)num[i]=vis[0];break;}}if(tag==0){for(i=1;i<=num[0];i++)if(!num[i])tag++;else break;for(i=1;i<=num[0]-tag;i++)num[i]=num[i+tag];num[0]-=tag;}}LL cal(char *num){LL ans=0;int i;for(i=1;i<=num[0];i++){ans*=3;ans+=ternary[num[i]];}return ans+1;}void subOne(char * num){int i,ans=1;for(i=num[0];i>0;i--){num[i]-=ans;if(num[i]<0)num[i]+=10;else ans=0;}for(i=1;i<=num[0];i++) if(!num[i])ans++;else break;for(i=1;i<=num[0]-ans;i++)num[i]=num[i+ans];num[0]-=ans;if(num[0]==0)num[0]=1;}void Cp(char *a,char *b){int i;a[0]=b[0];for(i=1;i<=a[0];i++)a[i]=b[i];}LL fun(char *num,int tag){if(num[0]==0)return 0;getCloseNum(num);return cal(num)-(tag?0:1);}LL find(char *num){int i,tag;char nextbit[50];tag=num[0]&1;Cp(nextbit,num);num[0]=num[0]/2+(num[0]&1);for(i=1;i<=nextbit[0]-1;i++)nextbit[i]=9;nextbit[0]--;nextbit[0]=nextbit[0]/2+(nextbit[0]&1);return fun(num,tag)+fun(nextbit,1-tag);}void format(char *num,int has){int i,flag=0,tag;if(!has){for(i=1;num[i];i++)num[i]-='0'; num[0]=i-1;}tag=num[0]&1;for(i=1;i<=num[0]/2;i++){if(num[num[0]/2+1-i]<num[num[0]/2+tag+i]) { flag=1;break;}if(num[num[0]/2+1-i]>num[num[0]/2+tag+i]) { flag=-1;break;}}if(flag<0){for(i=2;i<=num[0]/2+tag;i++){if(num[i])break;}if(num[1]==1&&i>(num[0]/2+tag)){--num[0];for(i=1;i<=num[0];i++)num[i]=9;}else{num[0]=num[0]/2+tag;subOne(num);num[0]=2*num[0]-tag;for(i=num[0]/2+tag+1;i<=num[0];i++)num[i]=9;}}}int main(){int cas;char a[50],b[50];ternary[8]=2;ternary[1]=1;ternary[0]=0;scanf("%d",&cas);while(cas--){scanf("%s%s",a+1,b+1);format(a,0);format(b,0);if(a[1]==0&&a[0]==1){printf("%lld\n",find(b));continue;}subOne(a);format(a,1);printf("%lld\n",find(b)-find(a));}return 0;}