URAL K-based Numbers(1-3)

来源:互联网 发布:宋仲基和杨洋长相知乎 编辑:程序博客网 时间:2024/05/21 17:59

题意:
内存限制: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\n", 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\n",             (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\n", f[n]%Mod);        else solve();    }    return 0;}
0 0