HDU 6093 Rikka with Number(康托展开)

来源:互联网 发布:java编程基础培训学校 编辑:程序博客网 时间:2024/06/10 16:59

Description

定义一个数K是好数当且仅当存在d2使得Kd进制下有d位且这d位的值是一个0~d1的排列,给出一个区间[L,R],问该区间中有多少个好数,结果模998244353

Input

第一行一个整数T表示用例组数,每组用例输入两个十进制数L,R(1T10,1LR105000)

Output

对于每组用例,输出区间[L,R]中好数的数量,结果模998244353

Sample Input

2
5 20
123456 123456789

Sample Output

3
114480

Solution

求出[1,n]好数即可,d进制下的好数,其最小值为(1,0,2,3,...,d1)d>dd1,其最大值为(d1,d2,...,0)d <dd,由(d+1)d>dd知相邻两个进制的好数不交,即不存在在两个不同的进制下都是好数的数,d进制下好数有d!(d1)!(即总排列数减去第一位是0的排列数),所以只需要考虑包含n的临界值即可,用对数估计得到d进制好数转化为十进制后的大致长度,对估计出的临界值的附近几个值(亲测两个值)去求解,把n转化为d进制后,类似康托展开的计数即可得到不大于nd进制好数

Code

#include<cstdio>#include<cmath>#include<cstring> using namespace std;typedef long long ll;#define maxn 5005#define mod 998244353int L[maxn],fact[maxn];void init(int n=5000){    int len=1;    while(L[len]<=n)    {        len++;        L[len]=log10(len)*(len-1);    }    fact[0]=1;    for(int i=1;i<=n;i++)fact[i]=(ll)i*fact[i-1]%mod;}int dec(int x,int y){    return x-y<0?x-y+mod:x-y;}int inc(int x,int y){    return x+y>=mod?x+y-mod:x+y;}int T,a[maxn],b[maxn],c[maxn],mark[maxn];char s[maxn];int Deal(int *a,int len,int m)//把a转化成m进制 {    int n=0;    for(int i=1;i<=len;i++)c[i]=a[i];    while(len)    {        if(n>m)return n;        int pre=0;        for(int i=len;i;i--)        {            int temp=pre*10+c[i];            pre=temp%m,c[i]=temp/m;        }        b[++n]=pre;        while(len&&c[len]==0)len--;    }    return n;}int Count(int *a,int len,int m){    int n=Deal(a,len,m);    if(n<m)return 0;    if(n>m)return dec(fact[m],fact[m-1]);    for(int i=0;i<n;i++)mark[i]=0;     int ans=(ll)(b[n]-1)*fact[n-1]%mod;    mark[b[n]]=1;    for(int i=n-1;i;i--)    {        for(int j=0;j<b[i];j++)            if(!mark[j])ans=inc(ans,fact[i-1]);        if(mark[b[i]])break;        mark[b[i]]=1;        if(i==1)ans=inc(ans,1);    }    return ans;}int Solve(int *a,int len){    if(len==0)return 0;    int pos=2;    while(L[pos]<len)pos++;    int ans=dec(fact[pos-3],1);    for(int i=pos-2;i<pos;i++)ans=inc(ans,Count(a,len,i));    return ans;}int main(){    init();    scanf("%d",&T);    while(T--)    {        scanf("%s",s+1);        int len=strlen(s+1);        for(int i=1;i<=len;i++)a[i]=s[len+1-i]-'0';        a[1]--;        for(int i=1;i<=len;i++)            if(a[i]<0)                a[i+1]--,a[i]+=10;        while(len&&a[len]==0)len--;        int ans=Solve(a,len);        scanf("%s",s+1);        len=strlen(s+1);        for(int i=1;i<=len;i++)a[i]=s[len+1-i]-'0';        ans=dec(Solve(a,len),ans);        printf("%d\n",ans);    }    return 0;}
原创粉丝点击