hdu6156 Palindrome Function 思维题

Problem Description
As we all know,a palindrome number is the number which reads the same backward as forward,such as 666 or 747.Some numbers are not the palindrome numbers in decimal form,but in other base,they may become the palindrome number.Like 288,it’s not a palindrome number under 10-base.But if we convert it to 17-base number,it’s GG,which becomes a palindrome number.So we define an interesting function f(n,k) as follow:
f(n,k)=k if n is a palindrome number under k-base.
Otherwise f(n,k)=1.
Now given you 4 integers L,R,l,r,you need to caluclate the mathematics expression  Ri=Lrj=lf(i,j)  .
When representing the k-base(k>10) number,we need to use A to represent 10,B to represent 11,C to repesent 12 and so on.The biggest number is Z(35),so we only discuss about the situation at most 36-base number.
 

Input
The first line consists of an integer T,which denotes the number of test cases.
In the following T lines,each line consists of 4 integers L,R,l,r.
( 1T105,1LR109,2lr36 )
 

Output
For each test case, output the answer in the form of “Case #i: ans” in a seperate line.
 

Sample Input
  
  
3 1 1 2 36 1 982180 10 10 496690841 524639270 5 20
 

Sample Output
  
  
Case #1: 665 Case #2: 1000000 Case #3: 447525746

ccpc的网络赛的题,说实话刚开始看上去是有一点蒙蔽的,后来想清楚怎么回事了。但是太菜,比赛的时候没有办法写出来,到了第二天早上开始写,

然后期间碰到了无数的bug,一直在找,一直在调试,终于在很长时间的努力之下过了这个题。虽然比赛没有做出来,但是只要努力,慢慢的,我也会成长很多的。

 题目大意:每个数在不同的进制下面可能变成回文串,给你t组数据,每组数据有四个数字,L,R,l,r,有个函数的意思是,数字i,在k进制下面是回文串,则函数值是k,否则函数值是1,让你计算数字L到R的每一个数字,在l到r进制下面的函数值之和。

其实进制最多也就2到36,我们可以算出L-1,R两个数字在l到r进制的函数直之茶,加起来就可以得到最终结果。这样快了很多。

所以最重要的问题是,知道0到L-1,0到R在不同的进制下面有几个回文串,所以问题就来到了,怎么统计出所有回文串。

这个问题上,我想了挺久的时间,最终一路磕磕盼盼,发现了如何统计的规律。

再写多一点,方便理解:

举个例子

10进制下面

0~0 有1个

0~10 :1+9=10;

0~20:  1+9+1 (11)=12

...

0~100=1+9 +9

0~1000=1+9+9+9×10

......

数据中的第二个数字来说。0~982180有几个10进制的回文串呢

先统计0~10^5有多少个回文串

然后就到了10^5到982180有多少个回文串了

这个步骤我详细解释一下

首先统计10^5到9×10^5:第一位数只能选1~8,一共8个数,第二位和第五位对应可以选0~9十个数,第三位和第四位对应.......就是8×10×10

然后如果要找9×10^5以后的数字,必须满足的是9 * * * *9对吧,所以就是982179,然后接着递归地去统计。

其中有点坑的是,比如到最后的时候,匹配到最后时候发现,只有一个数,或者两个数并且高位数比低位数小,那么最后的结果要加一。

比如统计0~33,我们会先统计0~10有十个,10到30有2个,最后还有30~33还有最后一个数33也是回文串

具体看代码吧,注意理解我说的坑。

最后注意一下,int可能会有溢出的问题,用long long

贴一下代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#define ll long long
#define read(a) scanf("%lld",&a);
using namespace std;
ll s[105];
ll len=0;
void change(ll num,ll ba){
	len=0;
	while(num){
		ll tmp=num%ba;
		s[++len]=tmp;
		num/=ba;
	}
	// for(ll i=len;i>=1;i--){
	// 	printf("%lld ",s[i]);
	// }
	// printf("\n");
	// printf("%lld\n",len);
}
ll dfs(ll left,ll right,ll num,ll ba,ll cur){
	if(left>right)
		return 0;
	ll i,j;
	i=left;
	j=right;
	ll temp;
	ll ans=0;
	if(cur==0){
		temp=s[j]-1;
	}
	else{
		temp=s[j];
	}
	if(temp>0){
		i++;
		j--;
		while(i<=j){
			temp*=ba;
			i++;
			j--;
		}
		ans+=temp;
	}
	if(left==right){
		ans++;
	}
	else if(s[left]>=s[right]&&left+1==right){
		ans++;
	}
	// for(ll p=1;p<=len;p++)
	// 	printf("%lld\n",s[p]);
	// printf("\n");
	ll tmp=pow(ba,right-left);
	tmp=num%tmp;
	tmp/=ba;
	//printf("%lld %lld %lld %lld\n",s[right],s[left],ans,tmp);
	//printf("%lld %lld\n",num,tmp);
	if(s[left]<s[right]){
		tmp--;
		if(tmp>=0){
			ll a=s[right]-s[left];
			ll k=left;
			s[k]=s[right];
			k++;
			s[k]--;
			while(s[k]<0){
				s[k]+=ba;
				s[k+1]--;
				k++;
			}
		}
	}
	if(tmp<0){
		return ans;
	}
	else{
		return ans+dfs(left+1,right-1,tmp,ba,cur+1);
	}
}
ll solve(ll num,ll ba){
	ll ans=1;
	for(ll i=1;i<len;i++){
		ll tmp=i;
		ll temp=ba-1;
		tmp-=2;
		while(tmp>0){
			temp*=ba;
			tmp-=2;
		}
		ans+=temp;
	}
	//printf("%lld\n",ans);
	ans+=dfs(1,len,num,ba,0);
	//printf("%lld\n",ans);
	return ans;
}
// ll dfs(ll left,ll right,ll num,ll ba){
// 	if(left>right)
// 		return 0;
// 	ll i=left,j=right;
// 	ll ans=0;
// 	ll temp=a[j]-1;
// 	while(temp>0){
// 		i++;
// 		j--;

// 	}
// }
int main(){
	freopen("test.txt","r",stdin);
	// change(496690840,12);
	// printf("%lld\n",solve(496690840,12));
	// for(ll i=2;i<=36;i++){
	// 	for(ll j=100000000;j<=1000000000;j++){

	// 	}
	// }
	ll t;
	scanf("%lld",&t);
	ll ans;
	ll ca=1;
	while(t--){
		ll L,R,l,r;
		ans=0;
		scanf("%lld %lld %lld %lld",&L,&R,&l,&r);
		for(ll i=l;i<=r;i++){
			change(R,i);
			ll ans1=solve(R,i);
			change(L-1,i);
			ll ans2=solve(L-1,i);
			ans+=(ans1-ans2)*(i-1);
			//ans=1980*9;
			printf("%lld %lld %lld %lld %lld %lld\n",L,R,i,ans1,ans2,ans1-ans2);
		}
		ans+=(R-L+1)*(r-l+1);
		printf("Case #%lld: %lld\n",ca++,ans);
	}
	return 0;
}

这个是当初为了发现错误,采用暴力算法,用来调试的代码

#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#define ll long long
#define read(a) scanf("%d",&a);
using namespace std;
int s[100];
int a[100];
int len;
int ba;
bool isper(int num){
	len=0;
	while(num){
		int tmp=num%ba;
		s[++len]=tmp;
		num/=ba;
	}
	int i=1;
	int j=len;
	while(i<=j){
		if(s[i]!=s[j]){
			return false;
		}
		i++;
		j--;
	}
	return true;
}
int main(){
	//freopen("test.txt","r",stdin);
	int num;
	int ans=0;
	int start;
	int a,b;
	while(~scanf("%d %d %d %d",&start,&num,&a,&b)){
		for(ba=a;ba<=b;ba++){
			ans=0;
			for(int i=start;i<=num;i++){
				if(isper(i)){
					ans++;
					//printf("%d %d\n",ans,i);
				}
			}
			printf("%d %d\n",ans,ba);
		}
	}
	return 0;
}

辛苦了一天,发现弄懂了一个题,也是很满足的,继续加油。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值