2017 多校5 Rikka with Number(数学 + 数位dp)

题意:

统计\([L,R]\)内 有多少数字 满足在某个\(d(d>=2)\)进制下是\(d\)的全排列的

\(1 <= L <= R <= 10^{5000}\)

题解:

首先转化成计算小于等于 \(N\)的好数有多少个。因为 \(n^n<(n+1)^n\)



​​而对于 \(n\) 进制下的任何一个好数 \(K\),都有 \(n^{n-1}<K<n^n
​\)

​​

​​ ,所以每一个进制下好数的大小区间是不相交的。

不难发现 \(d\) 进制下好数的个数为 \(d!-(d-1)!\)

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

求 \(d\) 进制下小于等于 \(N\) 的好数个数,先讲 \(N\) 转化成 \(d\) 进制,然后做一个类似康托展开的过程就可以了,因为数据范围很小,所以每一步操作都可以暴力进行。

时间复杂度 \(O(|R|^2)\)。

计算临界状态就用类似数位dp的做法,枚举数字,当不在上界的时候,后面的数字是可以取一个排列,直接算就好了

这样计数是线性的

ps: 做完这题还收获了一份大数模板

#include<bits/stdc++.h>
#define LL long long
#define P pair<int,int>
#define ls(i) seg[i].lc
#define rs(i) seg[i].rc
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ls rt<<1
#define rs (rt<<1|1)
using namespace std;
const int mod = 998244353;
const int MX = 5000;
const int MAXN = 9999;
const int DLEN = 4;
class Big {
public:
int a[MX], len;
Big(const int b = 0) {
int c, d = b;
len = 0;
memset(a, 0, sizeof(a));
while (d > MAXN) {
c = d - (d / (MAXN + 1)) * (MAXN + 1);
d = d / (MAXN + 1);
a[len++] = c;
}
a[len++] = d;
}
Big(const char *s) {
int t, k, index, L, i;
memset(a, 0, sizeof(a));
L = strlen(s);
len = L / DLEN;
if (L % DLEN) len++;
index = 0;
for (i = L - 1; i >= 0; i -= DLEN) {
t = 0;
k = i - DLEN + 1;
if (k < 0) k = 0;
for (int j = k; j <= i; j++) t = t * 10 + s[j] - '0';
a[index++] = t;
}
}
bool operator>(const Big &T)const {
int ln;
if (len > T.len) return true;
else if (len == T.len) {
ln = len - 1;
while (a[ln] == T.a[ln] && ln >= 0) ln--;
if (ln >= 0 && a[ln] > T.a[ln]) return true;
else return false;
} else return false;
}
bool operator==(const Big &T)const {
int ln;
if (len == T.len) {
ln = len - 1;
while (a[ln] == T.a[ln] && ln >= 0) ln--;
return ln < 0;
} else return false;
}
Big operator-(const Big &T)const {
int i, j, big;
bool flag;
Big t1, t2;
if (*this > T) {
t1 = *this;
t2 = T;
flag = 0;
} else {
t1 = T; t2 = *this; flag = 1;
}
big = t1.len;
for (i = 0; i < big; i++) {
if (t1.a[i] < t2.a[i]) {
j = i + 1;
while (t1.a[j] == 0) j++;
t1.a[j--]--;
while (j > i) t1.a[j--] += MAXN;
t1.a[i] += MAXN + 1 - t2.a[i];
} else t1.a[i] -= t2.a[i];
}
t1.len = big;
while (t1.a[t1.len - 1] == 0 && t1.len > 1) {
t1.len--;
big--;
}
if (flag) t1.a[big - 1] = 0 - t1.a[big - 1];
return t1;
}
int operator%(const int &b)const {
int i, d = 0;
for (int i = len - 1; i >= 0; i--) d = ((d * (MAXN + 1)) % b + a[i]) % b;
return d;
}
Big operator/(const int &b)const {
Big ret;
int i, down = 0;
for (int i = len - 1; i >= 0; i--) {
ret.a[i] = (a[i] + down * (MAXN + 1)) / b;
down = a[i] + down * (MAXN + 1) - ret.a[i] * b;
}
ret.len = len;
while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
return ret;
}
void print() {
printf("%d", a[len - 1]);
for (int i = len - 2; i >= 0; i--) printf("%d", a[i]);
}
int change(int m,int *s){ ///将大数转化成m进制,保存在字符串s 范围从1到len,并返回长度
int B[MX];
int Le=0; memcpy(B,a,sizeof a);
int tmp = len - 1;
while (tmp >= 0){
int x=0;
for (int i = tmp;i >= 0;i--){
int pre=x; x=(x*(MAXN+1)+B[i])%m; B[i]=(pre*(MAXN+1)+B[i])/m;
}
s[++Le]=x; while(tmp >= 0&&B[tmp]==0) tmp--;
}
return Le;
}
};
char sl[5050],sr[5050];
int f[2000];
int digit[MX];
int vis[MX];
int d;
void init(){
f[0] = 1;
for(int i = 1;i < 2000;i++) f[i] = 1LL * i * f[i-1] % mod;
}
void add(int &x,int y){
x += y;
if(x >= mod) x -= mod;
}
int dfs(int pos,int rbound,int leading_zero){
if(pos == 0) return 1;
if(!rbound) return f[pos];
int r = rbound?digit[pos]:d - 1;
int ans = 0,l = 0;
if(leading_zero) l++;
for(int i = l;i <= r;i++){
if(!vis[i]){
vis[i] = 1;
add(ans,dfs(pos - 1, i == r && rbound,0));
vis[i] = 0;
}
}
return ans;
}
int calc(Big x){
if(x == 0) return 0;
int len = x.change(10,digit),ans = 0;
for(d = 2;;d++){ ///先找到最大的d 在十进制下位数<=len 在d前面的可以直接算
if((int)((d+1)*log10(d+1))+1>len) break;
add(ans, 1LL*(d-1)*f[d-1]%mod);
}
while(1){///暴力枚举d,最多2个,把x转化为d进制的位数和d比较,若位数小于d,超过临界跳出
int pos = x.change(d,digit);
if(pos < d) break;
if(pos > d) add(ans, 1LL*(d-1)*f[d-1]%mod);
else {
memset(vis,0,sizeof(vis));
add(ans,dfs(pos,1,1));
}
d++;
}
return ans;
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
scanf("%s%s",sl,sr);
Big l = sl, r = sr;
printf("%d\n",(mod+calc(r)-calc(l-1))%mod);
}
return 0;
}

2017 多校5 hdu 6093 Rikka with Number的更多相关文章

  1. HDU 6093 - Rikka with Number | 2017 Multi-University Training Contest 5

    JAVA+大数搞了一遍- - 不是很麻烦- - /* HDU 6093 - Rikka with Number [ 进制转换,康托展开,大数 ] | 2017 Multi-University Tra ...

  2. 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence

    // 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence // 题意:三种操作,1增加值,2开根,3求和 // 思路:这题与HDU 4027 和HDU 5634 ...

  3. 2017 多校3 hdu 6061 RXD and functions

    2017 多校3 hdu 6061 RXD and functions(FFT) 题意: 给一个函数\(f(x)=\sum_{i=0}^{n}c_i \cdot x^{i}\) 求\(g(x) = f ...

  4. 2017 多校2 hdu 6053 TrickGCD

    2017 多校2 hdu 6053 TrickGCD 题目: You are given an array \(A\) , and Zhu wants to know there are how ma ...

  5. 2017 多校5 Rikka with String

    2017 多校5 Rikka with String(ac自动机+dp) 题意: Yuta has \(n\) \(01\) strings \(s_i\), and he wants to know ...

  6. HDU 6091 - Rikka with Match | 2017 Multi-University Training Contest 5

    思路来自 某FXXL 不过复杂度咋算的.. /* HDU 6091 - Rikka with Match [ 树形DP ] | 2017 Multi-University Training Conte ...

  7. HDU 6088 - Rikka with Rock-paper-scissors | 2017 Multi-University Training Contest 5

    思路和任意模数FFT模板都来自 这里 看了一晚上那篇<再探快速傅里叶变换>还是懵得不行,可能水平还没到- - 只能先存个模板了,这题单模数NTT跑了5.9s,没敢写三模数NTT,可能姿势太 ...

  8. HDU 6085 - Rikka with Candies | 2017 Multi-University Training Contest 5

    看了标程的压位,才知道压位也能很容易写- - /* HDU 6085 - Rikka with Candies [ 压位 ] | 2017 Multi-University Training Cont ...

  9. HDU 5831 Rikka with Parenthesis II(六花与括号II)

    31 Rikka with Parenthesis II (六花与括号II) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536 ...

随机推荐

  1. Json数据常用操作

    JSON字符串: var str1 = '{ "name": "cs", "sex": "man" }'; JSON对象 ...

  2. Spring Cloud 入门Eureka -Consumer服务消费(Ribbon)(二)

    前面一篇介绍了LoadBalancerClient来实现负载均衡, 这里介绍Spring cloud ribbon 1.ribbon Spring Cloud Ribbon 是一个基于Http和TCP ...

  3. 常见Linux的发行版有哪些?并描述不同发行版之间的联系与区别。

    一.按系列罗列linux的发行版,并描述不同发行版之间的联系和区别 Linux发行版=Linux内核+商业软件 linux的发行版: RedHat.Fedora.suse.红旗.debian.Ubun ...

  4. LVS基于NAT模式搭建负载均衡群集

    LVS的基本架构图 负载均衡群集中,包括三个层次的组件: 1.第一层,负载调度器(BL) 前段至少有一个负载调度器(Load Balancer 或称为Director)负责响应并分发来自客户端的访问请 ...

  5. thinkphp5,单图,多图,上传

    /** * 上传单图 */ function upload($path, $filename) { $file = request()->file($filename); $info = $fi ...

  6. Apache POI 工具类 [ PoiUtil ]

    pom.xml <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml ...

  7. Numpy安装报错:试过N种安装方法终于

    Import numpy时,会报下面的错误 /home/spyros/.local/lib/python2.7/site-packages/numpy/core/multiarray.so: unde ...

  8. B1071 小赌怡情 (15分)

    B1071 小赌怡情 (15分) 常言道"小赌怡情".这是一个很简单的小游戏:首先由计算机给出第一个整数:然后玩家下注赌第二个整数将会比第一个数大还是小:玩家下注 t 个筹码后,计 ...

  9. HyperLedger Fabric 1.4 区块链技术形成(1.2)

    在比特币诞生之时,没有区块链技术概念,当人们看到比特币在无中心干预的前提下,还能安全.可靠的运行,比特币网络打开了人们的想象空间:技术专家们开始研究比特币的底层技术,并抽象提取出来,形成区块链技术,或 ...

  10. 实时查询引擎 - Facebook Presto 介绍与应用

    1. Presto 是什么   Facebook presto是什么,继Facebook创建了HIVE神器后的又一以SQL语言作为接口的分布式实时查询引擎,可以对PB级的数据进行快速的交互式查询.它支 ...