ZOJ 4006Travel along the Line 数学推导+组合

ZOJ 4006Travel along the Line 数学推导+组合


传送门: https://zoj.pintia.cn/problem-sets/91827364500/problems/91827370217

题意

起 点 在 0 点 , 有 n 步 , 每 一 步 有 1 4 往 左 走 、 1 4 往 右 走 、 1 2 不 动 。 起点在0点,有n步,每一步有\frac{1}{4}往左走、\frac{1}{4}往右走、\frac{1}{2}不动。 0n414121
已 知 终 点 在 点 m , 问 所 有 方 案 到 达 m 时 P Q 是 多 少 , 请 对 1 e 9 + 7 取 模 。 已知终点在点m,问所有方案到达m时\frac{P}{Q}是多少,请对1e9+7取模。 mmQP1e9+7

思路

假 设 往 左 走 了 x 步 , 往 右 走 了 y 步 , z 步 不 动 , 即 可 得 : 假设往左走了x步,往右走了y步,z步不动,即可得: xyz
x 、 − x + y = m 、 x + y + z = n , 得 : x、-x+y=m、x+y+z=n,得: xx+y=mx+y+z=n
x > = 0 x>=0 x>=0
y = x + m ≥ 0 → x ≥ − m y=x+m\ge 0 \rightarrow x\ge -m y=x+m0xm
z = n − x − y ≥ 0 → x ≤ n − m 2 z=n-x-y\ge 0 \rightarrow x\leq \frac{n-m}{2} z=nxy0x2nm

所 以 x 的 范 围 为 [ m a x ( − m , 0 ) , n − m 2 ] 所以x的范围为[max(-m, 0),\frac{n-m}{2}] x[max(m,0),2nm]

对 于 每 一 个 x 的 贡 献 为 C n x ( 1 4 ) x ∗ C n − x y ( 1 4 ) y ∗ 1 2 z , 变 量 替 换 一 下 得 : 对于每一个x的贡献为C_n^x(\frac{1}{4})^x*C_{n-x}^y(\frac{1}{4})^y*\frac{1}{2}^z,变量替换一下得: xCnx(41)xCnxy(41)y21z
a n s = ( 1 2 ) n + m ∗ ∑ x = m a x ( − m , 0 ) n − m 2 C n x C n − x x + m ( 1 4 ) x ans=(\frac{1}{2})^{n+m}*\sum_{x=max(-m,0)}^{\frac{n-m}{2}}C_n^xC_{n-x}^{x+m}(\frac{1}{4})^x ans=(21)n+mx=max(m,0)2nmCnxCnxx+m(41)x

算 之 前 要 判 断 x 的 范 围 是 否 错 误 即 可 。 算之前要判断x的范围是否错误即可。 x

Code

#include "bits/stdc++.h"
using namespace std;

typedef long long ll;
ll mod = 1e9 + 7;

ll quick_pow(ll a, ll b) {
    ll ans = 1;
    while(b > 0) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans % mod;
}

const int N = 1e5 + 10;

ll f[N], inv[N], invF[N];

void Init() {
    f[0] = f[1] = inv[0] = inv[1] = invF[0] = invF[1] = 1;
    for(int i = 2;i < N; i++) {
        f[i] = f[i - 1] * i % mod;
        inv[i] = mod - (mod / i) * inv[mod % i] % mod;
        invF[i] = invF[i - 1] * inv[i] % mod;
    }
}

ll C(ll m, ll n) {
    if(m < 0 || n < 0 || n > m)
        return 0;
    ll ans = f[m];
    ans = ans * invF[n] % mod;
    ans = ans * invF[m - n] % mod;
    return ans;
}


void solve() {
    Init();
    int _; scanf("%d",&_);
    ll inv2 = quick_pow(2, mod - 2);
    ll inv4 = quick_pow(4, mod - 2);
    while(_--) {
        ll n, m;
        scanf("%lld%lld",&n,&m);
        if(abs(m) > n) {
            printf("0\n");
            continue;
        }
        ll xo = max(-m, 0ll), xn = (n - m) / 2;
        ll ans = quick_pow(inv2, n + m);
        ll res = 0;
        for(ll i = xo;i <= xn; i++) {
            res += quick_pow(inv4, i) * C(n, i) % mod * C(n - i, m + i) % mod;
            res %= mod;
        }
        ans = ans * res % mod;
        printf("%lld\n",(ans + mod) % mod);
    }
}

signed main() {
    solve();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值