您的位置:首页 > 其它

HDU 6093 Rikka with Number(康托展开)

2017-09-06 09:58 302 查看
Description

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

Input

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

Output

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

Sample Input

2

5 20

123456 123456789

Sample Output

3

114480

Solution

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

Code

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
#define maxn 5005
#define mod 998244353
int 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
]=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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: