Rikka with Number
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 79 Accepted Submission(s): 18
Problem Description
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 numberK=(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 oned≥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?
In radix d , a number
A number K is good if and only if there exists at least one
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≤105000) .
For each testcase, the first line contains two decimal numbers L,R(1≤L≤R≤105000) .
Output
For each testcase, print a single line with a single number – the answer modulo
998244353
.
Sample Input
2
5 20
123456 123456789
Sample Output
3
114480
题目大意:
给定一个区间 [L,R] ,判断区间中有多少个好数。
x 为好数的定义:
解题思路:
官方题解:
首先转化成计算小于等于
N
的好数有多少个。因为
不难发现
d
进制下好数的个数为
求
d
进制下小于等于
时间复杂度 O(|R|2) 。
代码:
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static int MAXN = 1600;
static BigInteger[] dx = new BigInteger[MAXN];
static long MOD = 998244353;
static long [] fac = new long [MAXN];
static void Init(){
dx[0] = BigInteger.ZERO;
dx[1] = BigInteger.ZERO;
for(int i=2; i<MAXN; i++){
dx[i] = BigInteger.ZERO;
for(int j=i-1; j>=0; j--){
dx[i] = dx[i].multiply(BigInteger.valueOf(i)).add(BigInteger.valueOf(j));
}
}
fac[0] = fac[1] = 1;
for(int i=2; i<MAXN; i++) fac[i]=fac[i-1]*i%MOD;
}
static int Low(BigInteger x){
int low=0, high=MAXN-1;
while(low < high){
int mid = (low+high)/2;
if(dx[mid].compareTo(x)>=0)high = mid;
else low = mid+1;
}
return high;
}
public static void main(String[] args){
Init();
Scanner in = new Scanner(System.in);
int T = in.nextInt();
for(int cas=1; cas<=T; cas++){
int [] vis = new int [MAXN];
for(int i=0; i<MAXN; i++) vis[i] = 0;
BigInteger L, R;
L = in.nextBigInteger();
R = in.nextBigInteger();
int dl = 0, dr = 0;
dl = Low(L)+1;
dr = Low(R)-1;
long ans = fac[dr]-fac[dl-1];
ans = (ans%MOD+MOD)%MOD;
if(dl > dr) ans = 0;
dl--; dr++;
long ans2=0;
BigInteger tmp = (BigInteger.valueOf(dl)).pow(dl-1);
for(int i=dl; i>=1; i--){
int top = L.divide(tmp).intValue();
if(i==dl && top==0) { ans2 = (ans2+fac[dl]-fac[dl-1])%MOD; break; }
int cnt=0;
for(int o=top+1;o<dl;o++) if(vis[o]==0) cnt++;
ans2 = (ans2+(cnt)*fac[i-1]%MOD)%MOD;
if(vis[top] == 1) break;
L = L.mod(tmp);
if(i==1 && vis[top]==0) ans2=ans2+1;
vis[top] = 1;
tmp = tmp.divide(BigInteger.valueOf(dl));
}
long ans1 = 0;
for(int i=0; i<MAXN; i++) vis[i] = 0;
tmp = (BigInteger.valueOf(dr)).pow(dr-1);
for(int i=dr; i>=1; i--)
{
int top = R.divide(tmp).intValue();
if(i==dr && top==0) {ans1 = (ans1+fac[dr]-fac[dr-1]%MOD); break;}
int cnt=0;
for(int o=top+1;o<dr;o++) if(vis[o]==0) cnt++;
ans1 = (ans1+(cnt)*fac[i-1]%MOD)%MOD;
if(vis[top] == 1) break;
R = R.mod(tmp);
vis[top] = 1;
tmp = tmp.divide(BigInteger.valueOf(dr));
}
ans = ans+ans2 + fac[dr]-fac[dr-1]-ans1;
if(dl==dr) ans=ans2-ans1;
ans = (ans%MOD+MOD)%MOD;
System.out.println(ans);
}
}
}