P4351 学习笔记
个人感觉这个题还是出得很好的,尤其是推式子有一步刚刚好吻合。
题目给了一个类似递推的式子,还给了矩阵的第一列 \(l_i\) 和第一行 \(t_i\),求 \(F{n,n}\)。
我们注意到 \(l_i\) 和 \(t_i\) 都是会被重复计算的。
所以我们计算其对于此矩阵的贡献(对于 \(F_{n,n}\) 的贡献)即可。
- 位于 \((k,1)\) 的 \(x\):我们稍微推一下,下表中记录 \(x\) 的系数
| \(l_1\) | \(t_2\) | \(t_3\) | \(t_4\) | \(t_5\) |
|---|---|---|---|---|
| \(l_2\) | ||||
| \(l_3\) | ||||
| \(l_4\) | \(al_4\) | \(a^2l_4\) | \(a^3l_4\) | \(a^4l_4\) |
| \(l_5\) | \(abl_4\) | \(2a^2bl_4\) | \(3a^3bl_4\) | \(4a^4bl_4\) |
(上表中以 \(k=4\) 为例)
注意到 \(F_{5,5}\) 的 \(l_4\) 项系数是 \(4a^4b\),即
\[C_{2n-i-2}^{n-i} a^ib^{n-i}
\]
即通项公式
- 位于 \((1,k)\) 的 \(x\) 还是可以退一下,下表中记录:
| \(l_1,t_1\) | \(t_2\) | \(t_3\) | \(t_4\) | \(t_5\) |
|---|---|---|---|---|
| \(l_2\) | \(bt_3\) | \(abt_3\) | \(a^2bt_3\) | |
| \(l_3\) | \(b^2t_3\) | \(2ab^2t_3\) | \(3a^2b^2t_3\) | |
| \(l_4\) | \(b^3t_3\) | \(3ab^3t_3\) | \(6a^2b^3t_3\) | |
| \(l_5\) | \(b^4t_3\) | \(4ab^4t_3\) | \(10a^2b^4t_3\) |
注意到 \(F_{5,5}\) 的 \(t_3\) 项系数为 \(10a^2b^4\),即
\[C_{2n-i-2}^{n-i} a^{n-i}b^i
\]
在上面推的过程中你就会发现 \(F_{i,j-1}\) 和 \(F_{i-1,j}\) 及其对称,上面算出的结果也验证了这一点。
别忘了 \(+c\)(我怎么感觉我在写积分)
\[c\sum_{i=2}^n \sum_{j=2}^n C_{2n-i-j}^{n-i} a^{n-i} b^{n-j}
\]
接下来考虑如何化简,令 \(k=2n-i-j\),则原式即为
\[c\sum_{i=2}^n \sum_{j=2}^n C_{k}^{n-i} a^{n-i}b_{n-j}
\]
我们考虑改成枚举 \(k\) 和 \(i\),即
\[c\sum_{k=0}^{2n-4} \sum_{i=\max(k-n+2,0)}^{\min(k, n-2)} C_k^i a^{k-i}b^i
\]
由于 \(i\) 的求和上下界有 \(\min\) 有 \(\max\),考虑直接分成 \(i=k-n+2\) 开始的和 \(i=0\) 开始的,即 \(k-n+2 \ge 0\) 和 \(k-n+2<0\),即 \(k \le n-2\) 和 \(k>n-2\),正好对应 \(\min(k,n-2)\) 的条件(巧妙!)
\[c\sum_{k=0}^{n-2} \sum_{i=0}^k C_k^ia^{k-i}b_i+c\sum_{k=n-1}^{4n-2} \sum_{i=k-n+2}^{n-2} C_k^i a^{k-i} b^i
\]
前面部分中你会找到一个二项式定理
\[\sum_{i=0}^k C_k^i a^{k-i} b^i=(a+b)^k
\]
那么变成了
\[c\sum_{k=0}^{n-2} (a+b)^k+c\sum_{k=n-i}^{4n-2} \sum_{i=k-n+2}^{n-2} C_k^i a^{k-i}b^i
\]
后面我们并不好变形,我们令
\[f_k=\sum_{k-(n-2)}^{n-2} C_k^i a^{k-i} b^i
\]
变成
\[c\sum_{k=0}^{n-2} (a+b)^k+c\sum_{k=n-i}^{4n-2} f_k
\]
所以根据组合数的递推公式,有递推式
\[f_k=(a+b)f_{k-1}-C_{k-1}^{k-n+1} a^{n-1} b^{k-n+1}-C_{k-1}^{n-2} a^{k-n+1}b^{n-1}
\]
以优秀的时间复杂度 \(O(n)\) 解决了这道题。
写代码的时候我还用 Lucas 定理加速了一下,不加速应该也能过。
code
#include <bits/stdc++.h>
#define pub public:
#define pri private:
#define fri friend:
#define Ofile(s) freopen(s".in", "r", stdin), freopen (s".out", "w", stdout)
#define Cfile(s) fclose(stdin), fclose(stdout)
#define fast ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
using namespace std;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
using lb = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
constexpr int mod = 1e6 + 3;
constexpr int maxn = 2e5 + 5;
ll n, a, b, c;
ll ans;
ll t[maxn], l[maxn];
ll powa[maxn], powb[maxn]; // a 和 b 的乘方
ll f[maxn << 1], fac[maxn << 1]; // 阶乘和 f
ll facv[maxn << 1]; // 进一步加速组合数计算
ll binpow(ll a, ll b, ll p){ // 快速幂
ll res = 1;
while (b){
if (b & 1)
res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
ll C(ll n, ll m, ll p){ // 计算组合数
if (n < m)
return 0;
return fac[n] * facv[m] % p * facv[n - m] % p;
}
ll Lucas(ll n, ll m, ll p){ // Lucas 加速
if (!m)
return 1;
return Lucas(n / p, m / p, p) % p * C(n % p, m % p, p) % p;
}
void init() {
fac[1] = 1;
for (ll i = 2; i <= (n << 1); i++)
fac[i] = fac[i - 1] * i % mod;
powa[0] = powb[0] = 1;
for (ll i = 1; i <= n; i++){
powa[i] = powa[i - 1] * a % mod;
powb[i] = powb[i - 1] * b % mod;
}
facv[n << 1] = binpow(fac[n << 1], mod - 2, mod);
for (ll i = (n << 1) - 1; i >= 0; i--)
facv[i] = facv[i + 1] * (i + 1) % mod;
}
ll calcf(ll k){
ll res = 0;
for (ll i = k - (n - 2); i <= (n - 2); i++)
res += Lucas(k, i, mod) * powb[i] % mod * powa[k - i] % mod, res %= mod;
return res;
}
int main() {
freopen("std.in", "r", stdin);
freopen("std.out", "w", stdout);
fast;
cin >> n >> a >> b >> c;
for (ll i = 1; i <= n; i++)
cin >> l[i];
for (ll i = 1; i <= n; i++)
cin >> t[i];
init();
ll res = 1;
for (ll i = 0; i <= n - 2; i++){
if (i) res = (a + b) * res % mod;
ans = (ans + c * res % mod) % mod; // 计算前半部分
}
for (ll i = 2; i <= n; i++){
ll cur_res = Lucas(2 * n - i - 2, n - i, mod) * powa[n - 1] % mod * powb[n - i] % mod * l[i];
ans = (ans + cur_res) % mod; // 贡献1
}
for (ll i = 2; i <= n; i++){
ll cur_res = Lucas(2 * n - i - 2, n - i, mod) * powa[n - i] % mod * powb[n - 1] % mod * t[i];
ans = (ans + cur_res) % mod; // 贡献二
}
f[n - 1] = calcf(n - 1);
for (ll k = n - 1; k <= 2 * n - 4; k++){
if (k != n - 1){
f[k] = f[k - 1] * (a + b) % mod - Lucas(k - 1, k - n + 1, mod) * powa[n - 1] % mod * powb[k - n + 1] % mod + mod - Lucas(k - 1, n - 2, mod) * powa[k - n + 1] % mod * powb[n - 1] % mod;
f[k] = (f[k] + mod) % mod;
}
ans = (ans + c * f[k] % mod) % mod; // 计算 f
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号