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=L∑rj=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.
In the following T lines,each line consists of 4 integers L,R,l,r.
( 1≤T≤105,1≤L≤R≤109,2≤l≤r≤36 )
3 1 1 2 36 1 982180 10 10 496690841 524639270 5 20
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;
}
辛苦了一天,发现弄懂了一个题,也是很满足的,继续加油。