【考试记录】4.8 Table ( 数论数学 --组合数 & 杨辉三角)

陆陆续续的开始考很多的试,也会更新这些题目记录下来,免得做完了之后毫无印象,就这么水过去了(以前的考试都是如此,哎……)

Table (T1) :

【考试记录】4.8 Table ( 数论数学 --组合数 & 杨辉三角)

样例:

【考试记录】4.8 Table ( 数论数学 --组合数 & 杨辉三角)

  出于对数学题本能的恐惧考场上放弃了此题专攻T2 T3....事实证明其实这题是可做的。

  我们发现其实这个图形就是一个广义上的杨辉三角:C(i, j) = a *  C (i - 1, j)+ b * C (i - 1, j - 1); 我们可以形成一个最暴力的想法:通过第p行的数据暴力推算出其他行的数据,打成表格后输出。但我们分析这样做的本质:将每一个格子的贡献层层下传 / 上析,最后传到我们所需要查询的(x,y)格子上。所以我们联想到:如果能够直接计算出第p行上每一个格子对所求(x,y)的贡献,不就能够算出来了吗?

  下面:

【考试记录】4.8 Table ( 数论数学 --组合数 & 杨辉三角)

下面写一点点自己最开始看的时候没有太懂/没注意到的地方:

  1:向右走:C(i, j) = C(i - 1, j - 1) + C(i - 1, j); C(i - 1, j) = C(i - 1, j - 1) - C(i, j); 所以对一个节点产生贡献的点即为它左侧&下方的点。

  2:a非常的大,所以不能用快速幂计算出a后再取逆元,应处理出powa & powb数组。

  3:处理组合数时,注意到因为n & m 有一个是不变的,所以可以快速线性递推求解。

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxn 10100100
#define int long long
#define mod 998244353
int m, n, a, b, p, q, f[];
int invc[maxn], inv[maxn], powa[maxn], powb[maxn];
int inva[maxn], C[maxn];
bool flag = ; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} int poww(int x, int t)
{
int base = ;
for(; t; t >>= , x = (x * x) % mod)
if(t & ) base = (base) * x % mod;
return base;
} void pre()
{
inv[] = inv[] = ;
for(int i = ; i < maxn; i ++)
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
inva[] = poww(a, mod - ), powa[] = powb[] = ;
powa[] = a, powb[] = b;
for(int i = ; i < maxn; i ++)
{
inva[i] = inva[i - ] * inva[] % mod;
powa[i] = powa[i - ] * a % mod;
powb[i] = powb[i - ] * b % mod;
}
} void work1(int x, int y)
{
int lim = min(x - p, y - ), ret = ; C[] = ;
for(int i = ; i <= lim; i ++)
C[i] = C[i - ] * (x - p - i + ) % mod * inv[i] % mod;
for(int i = ; i <= lim; i ++)
{
int tem = f[y - i] * powb[i] % mod;
tem = (tem * powa[x - p - i]) % mod * C[i] % mod;
ret = (ret + tem) % mod;
}
printf("%lld\n", (ret + mod) % mod);
} void work2(int x, int y)
{
int ret = , k = p - x + y; C[p - x - ] = ;
for(int i = p - x; i <= k - ; i ++)
C[i] = C[i - ] * i % mod * inv[i - p + x + ] % mod;
for(int i = ; i <= y; i ++)
{
int tem = f[i] * poww(- b, y - i) % mod;
tem = tem * C[k - i - ] % mod;
tem = tem * inva[k - i] % mod;
ret = (ret + tem) % mod;
}
printf("%lld\n", (ret + mod) % mod);
} signed main()
{
freopen("table.in","r",stdin);
freopen("table.out","w",stdout);
m = read(), n = read(), a = read(), b = read();
p = read(), q = read();
pre();
for(int i = ; i <= n; i ++) f[i] = read();
for(int i = ; i <= q; i ++)
{
int x = read(), y = read();
if(x == p) printf("%lld\n", f[y]);
else if(x > p) work1(x, y);
else work2(x, y);
}
return ;
}
上一篇:51nod 1119【杨辉三角】


下一篇:javascript数组总结(0504)