2017 多校5 hdu 6093 Rikka with Number
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的更多相关文章
- HDU 6093 - Rikka with Number   |  2017 Multi-University Training Contest 5
		JAVA+大数搞了一遍- - 不是很麻烦- - /* HDU 6093 - Rikka with Number [ 进制转换,康托展开,大数 ] | 2017 Multi-University Tra ... 
- 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence
		// 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence // 题意:三种操作,1增加值,2开根,3求和 // 思路:这题与HDU 4027 和HDU 5634 ... 
- 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 ... 
- 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 ... 
- 2017 多校5 Rikka with String
		2017 多校5 Rikka with String(ac自动机+dp) 题意: Yuta has \(n\) \(01\) strings \(s_i\), and he wants to know ... 
- HDU 6091 - Rikka with Match   |  2017 Multi-University Training Contest 5
		思路来自 某FXXL 不过复杂度咋算的.. /* HDU 6091 - Rikka with Match [ 树形DP ] | 2017 Multi-University Training Conte ... 
- HDU 6088 - Rikka with Rock-paper-scissors   |  2017 Multi-University Training Contest 5
		思路和任意模数FFT模板都来自 这里 看了一晚上那篇<再探快速傅里叶变换>还是懵得不行,可能水平还没到- - 只能先存个模板了,这题单模数NTT跑了5.9s,没敢写三模数NTT,可能姿势太 ... 
- HDU 6085 - Rikka with Candies  |  2017 Multi-University Training Contest 5
		看了标程的压位,才知道压位也能很容易写- - /* HDU 6085 - Rikka with Candies [ 压位 ] | 2017 Multi-University Training Cont ... 
- HDU 5831 Rikka with Parenthesis II(六花与括号II)
		31 Rikka with Parenthesis II (六花与括号II) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536 ... 
随机推荐
- CI的子目录控制器问题
			不管是根目录还是子目录里面的文件名必须是首字母大写,否则会报404 
- flask实现基于elasticsearch的关键词搜索建议
			1.实现效果 2.fuzzy模糊查询和suggest查询 fuzzy模糊查询 GET chaxun/job/_search { "query": { "fuzzy&quo ... 
- javascript遍历方法总结
			forEach 循环 JavaScript诞生已经有20多年了,我们一直使用的用来循环一个数组的方法是这样的: for (var index = 0; index < myArray.lengt ... 
- java @override 全部报错
			问.java @override 全部报错 答: 错误:在 eclipse 的新工作空间开发项目时,出现大面积方法编译错误.鼠标放在方法名上后显示让我们去掉 @override 注解 原因: @Ove ... 
- #Python编程从入门到实践#第二章笔记
			1.变量 (1)变量名只能包含字母.数字和下划线,不能包含空格 (2)不要将python关键字与函数名作为变量名 (3)简短有描述性,避免使用小写字母l和大写字母O (4)python 始终 ... 
- 希尔排序算法Java实现
			希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进.该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 希尔排序实质上是一种分组插入方法.它的基本思想是: ... 
- easypoi 一行代码搞定excel导入导出
			开发中经常会遇到excel的处理,导入导出解析等等,java中比较流行的用poi,但是每次都要写大段工具类来搞定这事儿,此处推荐一个别人造好的轮子[easypoi],下面介绍下“轮子”的使用. pom ... 
- JS实现禁用滑动条但滑动条不消失的效果
			//方法 //滑动条 // left: 37, up: 38, right: 39, down: 40, // spacebar: 32, pageup: 33, pagedown: 34, end: ... 
- 笔记-git-.gitignore
			笔记-git-.gitignore 1. git忽略文件 有的文件不需要提交到公共仓库中,为此git提供了三种实现方式. gitignore文件 在项目的设置中指定排除文件 定义全局.git ... 
- jquery跨域解决方案JSONP
			1.在互联网中我们的计算机是通过IP来定位的,但是IP比较难记忆,因此通过domain name(域名)来取代IP 2.什么是跨域? (1)默认浏览器为了安全问题,禁止了xmlhttprequest跨 ... 
