Palindrome Function
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Others)Total Submission(s): 809 Accepted Submission(s): 446
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
题意:给出L,R,l,r。求从进制l到进制r,数L与R之间回文数字个数。这道题一看就是数位dp,然后听说是模板题,其实,我码了一个数位dp,然后改了改,结果发现,其实不用数位dp也可以搞定,只需要一点预处理,就可以解决了。(其实是因为我不擅长数位dp)
题解:1、先预处理一个sum[i][j] 数组,为i进制下的j位没有限制且首位不为0的所有回文数的个数。然后做一下前缀和,就可以得到i进制下0到长度为j的回文数个数。
2、用0到R的回文数个数减去0到L-1的回文数个数就得到L到R中回文数个数。
3、对于当前询问的数字,先将其分解成当前进制下的数组,长度为len,然后现在目标即是算出在长度为len的受到限制且首位不为0的回文数个数,首先知道,在一个数字,比如654321中,前三位还没到达654前,后三位是没有限制的,于是回文数个数tmp = 654 - 99(这个99的意思是:因为你1到654中有1位数2位数3位数,所以有001这样的数,违反了我们前面定义的首位不为0,故将此部分减去),然后,此时tmp还有一点需要考虑,即当到达654时,是否可行(因为此时后三位已受到限制),这时就从中间枚举,即枚举这里的3,2,1,如果该位比其对应的那个对称数小,说明tmp-1(3小于4,不存在654456)如果该位比其对应得那个对称数大(假设原来要求的数为654500,5大于4,存在654456),则tmp不用减1,同样的,如果一直等下去,说明该树本身就是回文数,tmp一样不用减1。
4、此时我们找到sum[当前进制][长度为len-1],加上第3步求出来的tmp,就是0到该数的回文数个数。
5、按第2步做,做差相乘加和得到答案。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <functional>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
typedef long long ll;
const double eps = 1e-7;
const int maxn = 3e5+7;
const int INF = 1e9+7;
ll sum[40][40];
ll l,r,L,R,d,len;
ll b[40];
ll qpow(ll a,ll b){
ll ans = 1;
while(b){
if(b&1){
ans*=a;
}
a*=a;
b>>=1;
}
return ans;
}
ll solve(ll a,ll bit){
if(a==0) return 1;
len = 0;
while(a){
b[len++] = a%bit;
a/=bit;
}
d = len - (len-1)/2 - 1;
int nlen = (len-1)/2 + 1;
ll tmp = 0;
for(int i = len-1;i >= d;i--){
tmp*=bit;
tmp+=b[i];
}
tmp-=qpow(bit,nlen-1)-1;
int flag = 1;
for(int i = nlen-1;i >= 0;i--){
if(b[i]>b[len-i-1]){
flag = 1;
break;
}
else if(b[i]<b[len-i-1]){
flag = 0;
break;
}
}
if(!flag) tmp-=1;
//cout<<tmp<<" "<<sum[bit][len-1]<<endl;
return tmp+sum[bit][len-1];
}
int main(){
memset(sum,0,sizeof(sum));
for(int i = 2;i <= 36;i++){
sum[i][1] = sum[i][0] = 1;
}
for(int i = 2;i <= 36;i++){
for(int j = 1;j < 40;j++){
sum[i][j] += qpow(i,(j-1)/2)*(i-1);
if(j!=1) sum[i][j] += sum[i][j-1];
}
}
int t;
scanf("%d",&t);
int I = 1;
while(t--){
scanf("%lld %lld %lld %lld",&L,&R,&l,&r);
ll ans = 0;
ll all = R-L+1;
for(int i = l;i <= r;i++){
ll tmp = solve(R,i)-solve(L-1,i);
ans+=tmp*i+all-tmp;
}
printf("Case #%d: ",I++);
cout<<ans<<endl;
}
return 0;
}