HDU 6093 Rikka with Number(java大数+思维)

来源:互联网 发布:阿里云机房地址 编辑:程序博客网 时间:2024/06/08 17:50

传送门

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 number K=(A1A2...Am)d(Ai[0,d),A10) is good if and only A1Am is a permutation of numbers from 0 to d1.

A number K is good if and only if there exists at least one d2 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(1t20), the number of the testcases.

For each testcase, the first line contains two decimal numbers L,R(1LR105000).
 

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 为好数的定义:x 在 任意 d 进制下,可以表示为 [0,d1] 的排列。

解题思路:

官方题解:


首先转化成计算小于等于 N 的好数有多少个。因为 nn(n+1)n,而对于 n 进制下的任何一个好数 K,都有 nn1nn,所以每一个进制下好数的大小区间是不相交的。

不难发现 d 进制下好数的个数为 d!(d1)!,因此我们只需要计算在临界的 d 进制下,好数的个数就可以了。关于临界的 d,可以用对数估计位数得到。

d 进制下小于等于 N 的好数个数,先讲 N 转化成 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);        }    }}