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
定义一个数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; }
相关文章推荐
- HDU 6093 Rikka with Number
- [HDU 6093] Rikka with Number
- HDU 6093 Rikka with Number (2017 Multi-Univ Training Contest 5)
- HDU 6093 Rikka with Number (2017 Multi-University Training Contest - Team 5)
- HDU 6093 Rikka with Number(java大数+思维)
- hdu 5423 Rikka with Tree(思路)
- hdu5632 Rikka with Array 数位dp
- hdu 5423 Rikka with Tree(dfs)
- hdu 5422 Rikka with Graph
- HDU 5202 Rikka with string
- HDU-2017 多校训练赛5-1008-Rikka with Subset
- Hdu 6090 Rikka with Graph【贪心】
- hdu 6090 Rikka with Graph
- HDU 5630 Rikka with Chess
- Rikka with Subset(HDU 6092)
- HDU 6090 Rikka with Graph (贪心+构造, 2017 Multi-Univ Training Contest 5)
- HDU 6095 Rikka with Competition【】
- hdu 6086 Rikka with String(AC自动机+状压dp)
- 【多校训练】 hdu 6092 Rikka with Subset
- Rikka with Subset HDU - 6092 (傻瓜01背包)