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;
}
原文地址:https://www.cnblogs.com/pbvrvnq/p/8530152.html