#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. 御神体的主要内容,如果未能解决你的问题,请参考以下文章