SPOJ10649 Mirror Number(三进制回文)

/*

题目: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 long
int 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;
}





 

你可能感兴趣的:(SPOJ10649 Mirror Number(三进制回文))