HDU 6093 Rikka with Number
题目描述:
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:
In radix d, a number K=(A1A2...Am)d(Ai∈[0,d),A1≠0) is good if and only A1−Am is a permutation of numbers from 0 to d−1.
A number K is good if and only if there exists at least one d≥2 and K is good under radix d.
Now, Yuta wants to calculate the number of good numbers in interval [L,R]
It is too difficult for Rikka. Can you help her?
Input
The first line contains a number t(1≤t≤20), the number of the testcases.
For each testcase, the first line contains two decimal numbers L,R(1≤L≤R≤10^5000).
Output
For each testcase, print a single line with a single number -- the answer modulo 998244353.
链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6093 (2017 Multi-University Training Contest - Team 5)
题目大意:
模拟题,给一个L到R的闭区间,求区间内的good number的数量(1≤L≤R≤1e5000)。
对于good number的定义:
将一个数字num转换为k进制,恰好为0 - k-1的k个数字的一种排列组合(不包括前导0),则num为一个good number。
分析:
对于x位d进制数转换成10进制数字num后,num的位数y满足条件:d^x=10^y,得y = (x-1) * log(d) / log(10)。 由于本题的数据范围很大,需要进行高精度的进制转换。 d进制的good number的数量为d!-(d-1)!。其十进制数对应的范围为(d^(d-1),d^d)。 对于问题,可以求解[0,L-1]区间的good number,与[0,R]区间的good number,它们的差即为answer。 根据4.结论,本问题转换为求解[0,i]区间内的good number的个数,根据1.与3.可以判断出该区间内的good number来源的进制d的范围,枚举每个d即可得到答案。 对于过程5.可以优化,当d>15时,[2,d-2]区间的进制对应的good number一定包含在[0,L-1]区间内,只需计算d-1、d进制所产生的good number是否在本区间内即可。 对于6.中的计算,可以采用类似康托展开定理的方式进行枚举。
代码:
#include<bits/stdc++.h>
using namespace std ;
const int maxn = 5000 +50 ;
const int mod=998244353 ;
vector <double > base;int len_base;
int jc[maxn];
char l[maxn],r[maxn];
int rl[maxn],rr[maxn],len_rl,len_rr;
void base_init();
void get_jc();
void get_rs(char *s,int num,int *rs,int &l);
int get_base(int len);
int calc(int *s,int len,int d);
int get_ans(char *s,int num,int *rs,int &l);
int main()
{
base_init();
get_jc();
int t;scanf ("%d" ,&t);
while (t--){
scanf ("%s" ,l);
int ans = get_ans(l,1 ,rl,len_rl);
scanf ("%s" ,r);
ans = (get_ans(r,0 ,rr,len_rr)-ans+mod)%mod;
printf ("%d\n" ,ans);
}
return 0 ;
}
void base_init(){
base.push_back(0 );base.push_back(0 );
for (int i=2 ;;i++){
base.push_back((i-1 )*log (i)/log (10 ));
len_base = i;
if ((i-1 )*log (i)/log (10 )>5000 )break ;
}
}
void get_jc(){
jc[0 ]=1 ;
for (int i=1 ;i<=len_base;i++) jc[i] = (long long )jc[i-1 ]*i%mod;
}
int get_ans(char *s,int num,int *rs,int &l){
get_rs(s,num,rs,l);
int d=get_base(l);
int ans = 0 ;
if (d>15 ){
for (int i=2 ;i<=d-2 ;i++)ans=((long long )ans+jc[i]-jc[i-1 ]+mod)%mod;
ans =((long long )ans+calc(rs,l,d-1 ))%mod;
ans =((long long )ans+calc(rs,l,d))%mod;
}
else
for (int i=2 ;i<=d;i++) ans =((long long )ans+calc(rs,l,i))%mod;
return ans;
}
void get_rs(char *s,int num,int *rs,int &l){
int len = strlen (s);
for (int i=0 ;i<len;i++)
rs[i]=s[len-1 -i]-'0' ;
rs[0 ]-=num;
for (int i=0 ;i<len;i++) while (rs[i]<0 )rs[i+1 ]--,rs[i]+=10 ;
l=0 ;
for (int i=len-1 ;i>=0 ;i--)
if (rs[i]!=0 ){l=i+1 ;break ;}
}
int get_base(int len){
for (int i=1 ;i<=len_base;i++)
if (base[i]>len) return i-1 ;
}
int calc(int *s,int len,int d){
int temp[maxn],changes[maxn],len_changes=0 ;
memcpy (temp,s,sizeof (int )*len);
while (len){
int x=0 ;
for (int i=len-1 ;i>=0 ;i--){
int pre=x; x=(x*10 +temp[i])%d; temp[i]=(pre*10 +temp[i])/d;
}
changes[len_changes++]=x; while (len&&temp[len-1 ]==0 ) len--;
}
if (len_changes>d) return (jc[d]-jc[d-1 ]+mod)%mod;
if (len_changes<d) return 0 ;
int point[maxn];
for (int i=0 ;i<d;i++) point[i]=0 ;
int res = 0 ;
for (int i=1 ;i<changes[len_changes-1 ];i++) res=((long long )res+jc[d-1 ])%mod;
point[changes[len_changes-1 ]]=1 ;
for (int i=len_changes-2 ;i>=0 ;i--){
for (int j=0 ;j<changes[i];j++) if (point[j]==0 ) res =((long long )res + jc[i])%mod;
if (point[changes[i]])break ;
point[changes[i]]=1 ;
if (i==0 ) res =(res+1 )%mod;
}
return res;
}