zoukankan      html  css  js  c++  java
  • URAL K-based Numbers(1-3)

    题意:
    内存限制:1000K
    我们定义一个合法的K进制数为一个不含连续两个零的K进制数。
    例如:
    1010230 是一个合法的7位数。
    1000198 不是合法的数。
    0001234 不是7位数,是一个合法的4位数。

    给你N,和K,M求出N位的K进制数的总数模M的值

    这个是Version 3的翻译,其实建议直接做Version 3,当然,如果想感受一下这个好题的魅力,可以从第一题一直做到第三题,下面讲讲每个部分

    • Version 1

      可以发现数据范围很小,这意味着答案并不会很大,考虑用递推的办法解决问题,设f[i]为k进制下i位的答案,那么开始寻求递推公式,注意这里很重要,后面两个题的解决都和这一个公式有着很大的关系。
      我们先考虑当前这一位的决策,取0或不取0,不取0的情况是一定成立的,那么如果取0的话,i-1位一定不能取0,那么第i位取0的情况就只能搭配(f[i-2]*(k-1))这就是i-1位不为0的情况,然后直接推就好了

    #include <cstdio>
    #include <algorithm>
    
    const int N = 20;
    typedef long long LL;
    
    #define rep(i, s, t) for(LL i = s; i <= t; ++i)
    
    LL f[N];
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("input.in", "r", stdin);
        freopen("res.out", "w", stdout);
    #endif
        LL n, k;
        scanf("%lld%lld", &n, &k);
        f[1] = k-1;
        rep(i, 2, n)
            f[i] = (f[i-1]+f[i-2])*(k-1);
        printf("%lld
    ", f[n]+f[n-1]);
        return 0;
    }
    • Version 2
      同样的,还是可以采用1的方法,但是发现会超LL(其实数据不会但是别水好吧。。)我们就直接一波高精度秒
    #include <cstdio>
    #include <cstring>
    
    const int N = 2000 + 10;
    const int Mod = 1e4;
    #define max(a, b) a>b?a:b
    #define rep(i, s, t) for(int i = s; i <= t; ++i)
    #define dec(i, s, t) for(int i = s; i >= t; --i)
    
    struct BN {
        int x[N], len;
        BN() {len = 0, memset(x, 0, sizeof x);}
    
        void operator = (int d) {x[0] = d; len = 1;}
    
        void update() {
            rep(i, 0, len-1)
                if(x[i] >= Mod) x[i+1] += x[i]/Mod, x[i] %= Mod;
            while(x[len]) len++;
        }
    
        void print() {
            printf("%d", x[len-1]);
            dec(i, len-2, 0) printf("%.4d", x[i]);
            puts("");
        }
    }Temp, f[N];
    
    BN operator + (BN a, BN b) {
        Temp.len = max(a.len, b.len);
        rep(i, 0, Temp.len-1) 
            Temp.x[i] = a.x[i]+b.x[i];
        Temp.update();
        return Temp;
    }
    BN operator * (BN a, int d) {
        rep(i, 0, a.len-1) a.x[i] *= d;
        a.update(); return a;
    }
    
    int n, k;
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("input.in", "r", stdin);
        freopen("res.out", "w", stdout);
    #endif
        scanf("%d%d", &n, &k);
        f[0] = 1;
        f[1] = k-1;
        rep(i, 2, n) 
            f[i] = (f[i-1]+f[i-2])*(k-1);
        f[n].print();
        return 0;
    }

    调试是出现了不明未知错误,用比较黑暗的办法强行过的,当然不是打表。

    • Version 3
      好吧发现这个题给了模数,那当然好,但是发现n,k特别大,于是就只能矩阵快速幂,考虑用第一问的矩阵构造单位矩阵, 如下图
      f[i-2],f[i-1] — 0 k-1 f[i-1],f[i]
      f[i-1],f[i] — 1 k-1 f[i],f[i+1]
      其实和斐波那契差不多,稍作改变就好;
      有一个坑点,模数范围很大,需要使用快速加法,否则会爆LL,快速加法就是将乘法用类似快速幂的思想解决具体见代码
    #include <cstdio>
    #include <cstring>
    
    typedef unsigned long long LL;
    
    #define rep(i, s, t) for(int i = s; i <= t; ++i)
    
    LL n, k, Mod, f[3];
    struct Matrix { 
        LL x[2][2];
        Matrix() {memset(x, 0, sizeof x);}
        void pre() {
            x[0][0] = 0;
            x[1][0] = 1;
            x[0][1] = x[1][1] = (k-1)%Mod;
        }
    }unit;
    
    LL multy(LL a, LL b) {
        LL Ans = 0;
        for(; b; b >>= 1LL) {
            if(b & 1) Ans = (Ans+a)%Mod;
            a = (a+a) % Mod;
        }
        return Ans%Mod;
    }
    
    Matrix operator * (Matrix a, Matrix b) {
        Matrix Ans;
        rep(i, 0, 1)
            rep(j, 0, 1) 
                rep(k, 0, 1)
                    Ans.x[i][j] = (Ans.x[i][j]+multy(a.x[i][k], b.x[k][j]))%Mod;
        return Ans;
    }
    
    Matrix operator ^ (Matrix a, LL d) {
        Matrix Ans = a;
        for(--d; d; d >>= 1LL, a=a*a)
            if(d & 1LL) Ans = Ans*a;
        return Ans;
    }
    
    void solve() {
        unit.pre();
        unit = unit ^ (n-2);
        unit.x[0][1] %= Mod;
        unit.x[1][1] %= Mod;
        printf("%llu
    ", 
                (multy(f[1], unit.x[0][1])%Mod+multy(unit.x[1][1], f[2])%Mod)%Mod);
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("input.in", "r", stdin);
        freopen("res.out", "w", stdout);
    #endif
        while(~scanf("%llu%llu%llu", &n, &k, &Mod)) {
            f[1] = (k-1)%Mod;
            f[2] = multy(k, k-1)%Mod;
            if(n == 2) printf("%llu
    ", f[n]%Mod);
            else solve();
        }
        return 0;
    }
  • 相关阅读:
    docker安装软件初体验
    docker的安装------------------以centos为例
    DOS常用命令总结
    Windows批处理功能-bat
    KALI系统上W3AF(Web Application Attack and Audit Framework)安装部署技巧
    调试问题
    jmeter 5.2下载binary版本后直接解压报错
    【注释】IntelliJ IDEA添加注释的快捷键是什么?
    [mybatis]自动逆向工程
    [数据库]mysql MySQL报错-Access denied for user 'root'@'localhost' (using password: NO)
  • 原文地址:https://www.cnblogs.com/pbvrvnq/p/8530152.html
Copyright © 2011-2022 走看看