#4346. 御神体

Posted xjqxjq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#4346. 御神体相关的知识,希望对你有一定的参考价值。

题意
内存限制:512 MiB
时间限制:4000 ms

> 再往前走就是隐世了,要想回到这个世界,必须留下你最重要的东西来交换。

小`H`来到了一个神秘的世界。在这个世界中,所有的事物都是交错的。

要想从这个世界中逃出,小`H`需要回答 $q$ 个问题。

对于每一个问题,都有两个值 $ n_i , m_i $,你需要计算出下面这个式子的值:

$$sum _{i=0}^{n_i} sum _{j=0}^{m_i} inom{i}{j} [i+j equiv 0 mod 2] pmod {998244353}$$

在这个式子中,$inom{i}{j}$ 表示从 $i$ 个物品中选出 $j$ 个物品的方案数。

$n leq 10^6$ && $q leq 10^4$ || $n leq 10^5$ && $q leq 10^5$
题解

考虑杨辉三角

对于一列,隔一个取的和,我们可以通过列方程组解出

对于一行,隔一个取的和,可以通过上一行的前缀和得到

设询问的答案为 $f_{n,m}$ ,若计算出了 $f_{n,m}$ ,则可以 $O(1)$ 计算出 $f_{n+1,m}$,$f_{n-1,m}$,$f_{n,m+1}$,$f_{n,m-1}$

莫队即可

考虑到块的大小 $L$ ,发现效率可表示为 $qL+frac{n^2}{L}$ 可得当L取 $sqrt{frac{n^2}{q}}$ 时最优秀

代码

#include <bits/stdc++.h>
#define I inline
#define _(d) while(d(isdigit(c=getchar())))
using namespace std;char c;
I int Rd(){int x;_(!);x=c^48;_()x=(x<<3)+(x<<1)+(c^48);return x;}
const int N=1e6+5,P=998244353,i2=499122177;
int Q,jc[N],ny[N],b[N],B,ans[N],s0,s1,s2,s,ax,l,r;
struct O{int n,m,id;}q[100005];
I int K(int x,int y){
    int A=1;
    for (;y;y>>=1,x=1ll*x*x%P)
        if (y&1) A=1ll*A*x%P;
    return A;
}
I int C(int x,int y){
    if (x<y || y<0) return 0;
    return 1ll*jc[x]*ny[y]%P*ny[x-y]%P;
}
I int X(int x){if (x>=P) x-=P;return x;}
I bool cmp(O A,O B){
    return b[A.n]==b[B.n]?A.m<B.m:b[A.n]<b[B.n];
}
I void inc(){
    s=X(s+s2);if ((l+r+1)&1) s=X(s+P-C(l,r));
    s2=X(X(s2+s2)+P-C(l,r));l++;
    if (l&1) s1=X(s1+C(l,r));else s0=X(s0+C(l,r));
}
I void dec(){
    if (l&1) s1=X(s1-C(l,r)+P);else s0=X(s0-C(l,r)+P);
    l--;s2=1ll*X(s2+C(l,r))*i2%P;
    s=X(s-s2+P);if ((l+r+1)&1) s=X(s+C(l,r));
}
I void add(){
    r++;int t0=s0,t1=s1,z=C(l+1,r+1);s2=X(s2+C(l,r));
    if (l&1) s0=1ll*(z-t0+P)*i2%P,s1=1ll*(z+t0)*i2%P;
    else s0=1ll*(z+t1)*i2%P,s1=1ll*(z-t1+P)*i2%P;
    if (r&1) s=X(s+s1);else s=X(s+s0);
}
int main(){
    Q=Rd();for (int i=1;i<=Q;i++)
        q[i].n=Rd(),q[i].m=Rd(),q[i].id=i,
        ax=max(ax,max(q[i].n,q[i].m));
    B=(int)sqrt(1ll*ax*ax/Q)+1;
    jc[0]=1;for (int i=1;i<N;i++)
        jc[i]=1ll*i*jc[i-1]%P;
    ny[N-1]=K(jc[N-1],P-2);
    for (int i=N-1;i;i--)
        ny[i-1]=1ll*i*ny[i]%P;
    for (int i=0;i<=ax;i++) b[i]=i/B+1;
    sort(q+1,q+Q+1,cmp);
    for (int i=1;i<=Q;i++){
        if (b[q[i].n]!=b[q[i-1].n] || i<2){
            l=r=s1=0;s=s0=s2=1;
            while(l<q[i].n) inc();
            while(r<q[i].m) add();
        }
        while(l<q[i].n) inc();while(l>q[i].n) dec();
        while(r<q[i].m) add();ans[q[i].id]=s;
    }
    for (int i=1;i<=Q;i++) printf("%d
",ans[i]);
    return 0;
}

 

以上是关于#4346. 御神体的主要内容,如果未能解决你的问题,请参考以下文章

[线段树] Luogu P4346 IIIDX

JZOJ 4231. 寻找神格 (Standard IO)

[线段树] Jzoj P4231 寻找神格

为啥不能编译这个 C++ 模板代码?

2020 2.9

微信小程序代码片段