[多校联考]琪露诺数
题目
【题目背景】
琪露诺是住在雾之湖的冰之妖精,在幻想乡的妖精当中算是最强的。同时她也是幻想乡首屈一指的数学家,有自己的算术教室。她喜欢用九进制来表示数字,因为这样数字中就不含$9$了。
【题目描述】
对于一个十进制数$X$,它在九进制下表示为$Y$,如果$Y$是一个回文数字,那么我们称$X$是一个琪露诺数。请你找出$[L,R]$中有多少个琪露诺数。
【输入格式】
第一行一个非负整数$T$,表示询问的个数。
接下来$T$行,每行两个正整数$L$和$R$,表示该组询问对应的范围$[L,R]$。
【输出格式】
对于每个询问,输出一个整数,表示$[L,R]$中琪露诺数的个数。
【样例输入】
样例输入1 1 1 10 样例输入2 4 1 100 1 1000 1 10000 18 19
【样例输出】
样例输出1 9 样例输出2 19 92 203 0
【数据范围】
对于样例1:[1,10]中有以下琪露诺数:1、2、3、4、5、6、7、8、10,他们在九进制下分别表示为1、2、3、4、5、6、7、8、11。 对于30%的数据,R≤10000 对于40%的数据,R≤10^12 对于50%的数据,R≤10^30 对于100%的数据,R≤10^100,T≤20,1≤L≤R
【提示】
对于任何一种进制——$X$进制,就表示每一位置上的数运算时都是逢$X$进位。十进制是逢$10$进位,十六进制是逢$16$进位,二进制就是逢$2$进位,以此类推,$X$进制就是逢$X$进位。同一个数在不同进制下可能会表示成不同的样子,比如十进制数$13$在二进制下表示为$1101$,在九进制下表示为$14$。
回文数字的定义如下:最高位的数字等于最低位的数字,次高位的数字等于次低位的数字……以此类推。比如:$22$,、$313$、$6$等都是回文数字,而$12$、$321$等不是回文数字。特别的,回文数字不考虑前导$0$,所以$20$、$110$不是回文数字,而$0$是回文数字。
题解
一道比较简单的高精度题(虽然我在考试的时候没做出来)
我们先把问题用差分转化成区间$[1,R]$内的数量减区间$[1,L-1]$内的数量。
注意,$L-1$可能为$0$,此时需要特判。
然后问题就转化为求区间$[1,X]$内的数量。
我们可以很快的求出九进制下小于等于某个数的最大回文数字,方法如下:
考虑这个九进制数的前半部分不变
如果构造后半部分的话,会不会比当前大,如果不会那么构造出来的就是小于等于这个数的最大回文数字
否则把前半部分看成一个数进行减$1$操作,再重新构造
注意这个过程中可能会发生位数的变化,所以我们先把$X$转化为九进制数$Y$,求出九进制下小于等于$Y$的最大回文数字$Z$,再把$Z$转化回十进制数
实现中涉及高精度的进制转换和加减法。时间复杂度$O(T*len^2)$。
注意,回文数分为长度为奇数和长度为偶数两种情况,涉及构造后半部分的不同。
CODE我知道你们只看这个
1 #include<bits/stdc++.h> 2 using namespace std; 3 inline int qread(){ 4 #define cg (c=getchar()) 5 int x,f=1;char c; 6 while(cg<'0'||'9'<c)if(c=='-')f=-1; 7 for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48)); 8 return x*f; 9 #undef cg 10 } 11 template<class T>inline T Max(const T x,const T y){return x>y?x:y;} 12 const int MAXL=200; 13 int T; 14 string l,r,c; 15 string add(const string x,const string y){ 16 int a[MAXL+5]={},b[MAXL+5]={},len; 17 for(int i=0,siz=x.size();i<siz;++i)a[siz-i]=x[i]^48; 18 for(int i=0,siz=y.size();i<siz;++i)b[siz-i]=y[i]^48; 19 len=Max(x.size(),y.size()); 20 for(int i=1;i<=len;++i)a[i]+=b[i],a[i+1]+=a[i]/10,a[i]%=10; 21 if(a[len+1])++len; 22 string ret;ret.clear(); 23 for(int i=len;i>=1;--i)ret+=a[i]^48; 24 return ret; 25 } 26 string sub(const string x,const string y){ 27 int a[MAXL+5]={},b[MAXL+5]={},len; 28 for(int i=0,siz=x.size();i<siz;++i)a[siz-i]=x[i]^48; 29 for(int i=0,siz=y.size();i<siz;++i)b[siz-i]=y[i]^48; 30 len=Max(x.size(),y.size()); 31 for(int i=1;i<=len;++i){ 32 a[i]-=b[i]; 33 if(a[i]<0)a[i]+=10,--a[i+1]; 34 } 35 while(a[len]==0&&len>1)--len; 36 string ret;ret.clear(); 37 for(int i=len;i>=1;--i)ret+=a[i]^48; 38 return ret; 39 } 40 bool zero(const string x){ 41 for(int i=0,siz=x.size();i<siz;++i)if(x[i]!='0') 42 return false; 43 return true; 44 } 45 string trans(string x,int n,int m){ 46 if(zero(x))return "0"; 47 string res,ret;res.clear(),ret.clear(); 48 // cout<<"This is transform:x=="<<x<<";n=="<<n<<";m=="<<m<<endl; 49 while(!zero(x)){ 50 int r=0; 51 for(int i=0,siz=x.size();i<siz;++i){ 52 res+=(((r*n+x[i]-'0'))/m)+'0'; 53 r=(r*n+x[i]-'0')%m; 54 } 55 x=res; 56 res.clear(); 57 ret+=r+'0'; 58 } 59 reverse(ret.begin(),ret.end()); 60 return ret; 61 } 62 string palin(const string x){ 63 if(zero(x))return "0"; 64 // cout<<"come in!"<<endl; 65 bool flg=false; 66 for(int len=x.size(),i=(len-1)>>1;i>=0;--i){ 67 if(x[i]==x[len-i-1])continue; 68 if(x[i]>x[len-i-1]){flg=true;break;} 69 else{flg=false;break;} 70 } 71 string a,b;a.clear(),b.clear(); 72 for(int i=0,len=x.size();i<(len+1)>>1;++i)a+=x[i]; 73 for(int i=0,len=x.size();i<len>>1;++i)b+='8'; 74 a=trans(a,9,10); 75 if(flg)a=sub(a,"1"); 76 // cout<<a<<' '<<b<<endl; 77 return add(a,trans(b,9,10)); 78 } 79 signed main(){ 80 T=qread(); 81 while(T--){ 82 cin>>l>>r; 83 l=sub(l,"1"); 84 l=trans(l,10,9); 85 r=trans(r,10,9); 86 cout<<sub(palin(r),palin(l))<<endl; 87 } 88 return 0; 89 }
放心食用!