【NOI2018模拟4.2】table

Description:

这里写图片描述
这里写图片描述

题解:

做法1:

一行一行的看。

每次变换相当于乘上多项式(bx+a)。

所以可以搞出 (bx+a)(p1) ( b x + a ) − ( p − 1 )

乘第p行的数就可以还原出第一行,之后的用个组合数搞搞就行了。

(bx+a)(p1) ( b x + a ) − ( p − 1 ) 的话,只用n项就可以了,并不用全部。

可以先把bx+a求逆,然后快速幂,O(n log^2 n)看上去有点悬。

也可以用二次项展开求出 (bx+a)(p1) ( b x + a ) ( p − 1 ) 先,再求逆,这个就只用 O(n log n) O ( n   l o g   n )

做法2:

x>=p很简单,要考虑x < < <script type="math/tex" id="MathJax-Element-5"><</script>p怎么做。

重写一下方程,变成倒推的。

fi,j=(fi+1,jfi,j1b)/a f i , j = ( f i + 1 , j − f i , j − 1 ∗ b ) / a
=fi+1,j/a+fi,j1(b/a) = f i + 1 , j / a + f i , j − 1 ∗ ( − b / a )

这个可以再推一下方案数,类似于挡板问题。

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;

const int N = 1e7, M = 1e5, C = N + M;
const ll mo = 998244353;

int m, n, a, b, p, Q, x, y;
ll c[M + 5], d[M + 5], fac[C + 5], nif[C + 5], ans;
ll ca[C + 5], cb[M + 5], na[C + 5], nb[M + 5];
ll cc[M + 5];

ll ksm(ll x, ll y) {
    ll s = 1;
    for(; y; y /= 2, x = x * x % mo)
        if(y & 1) s = s * x % mo;
    return s;
}

ll Ci(ll a, ll b) { return fac[a] * nif[b] % mo * nif[a - b] % mo;}

int main() {
    freopen("table.in", "r", stdin);
    freopen("table.out", "w", stdout);
    fac[0] = 1; fo(i, 1, C) fac[i] = fac[i - 1] * i % mo;
    nif[0] = 1; nif[C] = ksm(fac[C], mo - 2);
    fd(i, C - 1, 1) nif[i] = nif[i + 1] * (i + 1) % mo;
    scanf("%d %d %d %d %d %d", &m, &n, &a, &b, &p, &Q);

    ca[0] = cb[0] = 1; ca[1] = a; cb[1] = b;
    na[0] = nb[0] = 1; na[1] = ksm(a, mo - 2); nb[1] = ksm(b, mo - 2);
    fo(i, 2, C) ca[i] = ca[i - 1] * ca[1] % mo, na[i] = na[i - 1] * na[1] % mo;
    fo(i, 2, M) cb[i] = cb[i - 1] * cb[1] % mo, nb[i] = nb[i - 1] * nb[1] % mo;
    cc[0] = 1; cc[1] = (ll) (mo - b) * ksm(a, mo - 2) % mo;
    fo(i, 2, M) cc[i] = cc[i - 1] * cc[1] % mo;

    fo(i, 1, n) scanf("%lld", &c[i]);

    for(; Q; Q --) {
        scanf("%d %d", &x, &y);
        if(x == p) {
            printf("%lld\n", c[y]);
        } else
        if(x < p) {
            int u = p - x;
            ans = 0;
            fo(i, 1, y) ans += c[i] * Ci(u + (y - i) - 1, u - 1) % mo * na[u] % mo * cc[y - i] % mo;
            printf("%lld\n", ans % mo);
        } else {
            int u = x - p;
            ans = 0;
            fo(i, max(1, y - u), y)
                ans += c[i] * Ci(u, y - i)  % mo * cb[y - i] % mo * ca[u - (y - i)] % mo;
            printf("%lld\n", ans % mo);
        }
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值