Codeforces 935D Fafa and Ancient Alphabet

题目链接

题意

给定两个(n)位的(m)进制数(s1,s2),所有出现的(0)均可等概率地被其他数字替换,求(s1gt s2)的概率。

思路

从高位到低位,根据每一位上相应的(0)的个数进行 分类讨论

计算每一位的时候加上这样一部分答案:比到该位恰能比出大小的情况数。

恰能比出大小意味着:高位全部相同,该位(s1gt s2),低位随便怎么取。

因此,需对两个数目进行记录:1. 前面有多少位是两者皆0;2. 后面还有多少个0没有确定。

另:(x)关于(mod)的乘法逆元为(x^{(mod-2)}),由费马小定理易得。

注意:要对(m)的幂次进行预处理。

Code

#include <bits/stdc++.h>
#define maxn 100010
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
int a[maxn], b[maxn];
LL rec[maxn*2];
LL poww(LL a, LL b) {
    LL ret = 1;
    while (b) {
        if (b&1) (ret *= a) %= mod;
        (a *= a) %= mod;
        b >>= 1;
    }
    return ret;
}
LL f(LL p, LL q) {
    return p * poww(q, mod-2) % mod;
}
LL GCD(LL a, LL b) { return b ? GCD(b, a%b) : a; }
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    LL NUM = (1LL*m*m%mod-m+mod)%mod * poww(2, mod-2) % mod;
    int tot=0;
    F(i, 0, n) { scanf("%d", &a[i]); if (!a[i]) ++tot; }
    F(i, 0, n) { scanf("%d", &b[i]); if (!b[i]) ++tot; }
    rec[0] = 1;
    F2(i, 1, tot) rec[i] = rec[i-1]*m%mod;
    LL q = poww(m, tot), p=0;
    int cnt=0, prev=0;
    F(i, 0, n) {
        if (a[i]&&b[i]) {
            if (a[i]>b[i]) (p += rec[cnt+tot-prev]) %= mod;
            if (a[i]!=b[i]) { printf("%I64d
", f(p, q)); return 0; }
        }
        else if (!a[i] && !b[i]) {
            prev += 2;
            (p += (rec[cnt+tot-prev] * NUM % mod)) %= mod;
            ++cnt;
        }
        else {
            ++prev;
            if (a[i]) (p += rec[cnt+tot-prev] * (a[i]-1) % mod) %= mod;
            else (p += (rec[cnt+tot-prev] * (m-b[i]) % mod)) %= mod;
        }
    }
    LL gcd = GCD(p, q);
    p /= gcd, q /= gcd;
    printf("%I64d
", f(p, q));
    return 0;
}

原文地址:https://www.cnblogs.com/kkkkahlua/p/8460498.html