传送门
解析:
总是忍不住要吐槽一句,这题面也太长了吧。。。
首先,肯定要把我们要求的东西推成一个式子,不然怎么可能做题。。。
设fif_ifi表示当前以iii为最大值的方案数。
那么iii之后的数显然是单调递减且连续,方案数为111。
考虑前i−1i-1i−1个位置,放法数就是∑j=1i−1fj\sum_{j=1}^{i-1}f_j∑j=1i−1fj
所以我们现在得到递推式fi=∑j=1i−1fjf_i=\sum_{j=1}^{i-1}f_jfi=∑j=1i−1fj,f1=1f_1=1f1=1。
转换一下fi=∑j=1i−1fj=∑j=1i−2fj+fi−1=2fi−1f_i=\sum_{j=1}^{i-1}f_j=\sum_{j=1}^{i-2}f_j+f_{i-1}=2f_{i-1}fi=j=1∑i−1fj=j=1∑i−2fj+fi−1=2fi−1
所以得到通项公式fi=2i−1f_i=2^{i-1}fi=2i−1
那么询问的答案就是Q(n,m)=∑i=1nCmi×2i−1Q(n,m)=\sum_{i=1}^{n}C_{m}^i\times 2^{i-1}Q(n,m)=∑i=1nCmi×2i−1
数据范围1e51e51e5,果断莫队。
令l=n,r=ml=n,r=ml=n,r=m
我们只需要找到根据l,rl,rl,r更新答案的较小复杂度方法就行了
幸运的是,这个式子在l±1l\pm 1l±1和r±1r \pm 1r±1的时候都有O(1)O(1)O(1)的转移方式。
首先lll的转移:
Q(l−1,r)=Q(l,r)−Crl×2l−1Q(l-1,r)=Q(l,r)-C_r^l\times 2^{l-1}Q(l−1,r)=Q(l,r)−Crl×2l−1Q(l+1,r)=Q(l,r)+Crl+1×2lQ(l+1,r)=Q(l,r)+C_r^{l+1}\times 2^{l}Q(l+1,r)=Q(l,r)+Crl+1×2l
这个转移十分显然,就是直接根据表达式转移。
而rrr的转移需要一点技巧:
怎么求Q(l,r+1)=∑i=1lCr+1i×2i−1Q(l,r+1)=\sum_{i=1}^lC_{r+1}^{i}\times 2^{i-1}Q(l,r+1)=∑i=1lCr+1i×2i−1
由于帕斯卡三角形上的组合数递推公式Cn+1m=Cnm+Cnm−1C_{n+1}^m=C_n^m+C_n^{m-1}Cn+1m=Cnm+Cnm−1。我们把上面这个式子拆开得到∑i=1l(Cri+Cri−1)×2i−1=∑i=1lCri×2i−1+2×∑i=1l−1Cri×2i−1+Cr0×20\sum_{i=1}^{l}(C_r^i+C_r^{i-1})\times 2^{i-1}=\sum_{i=1}^{l}C_r^i\times 2^{i-1}+2\times\sum_{i=1}^{l-1}C_r^{i}\times2^{i-1}+C_r^0\times 2^0i=1∑l(Cri+Cri−1)×2i−1=i=1∑lCri×2i−1+2×i=1∑l−1Cri×2i−1+Cr0×20
所以其实就是Q(l,r+1)=Q(l,r)+2×Q(l−1,r)+Cr0×20Q(l,r+1)=Q(l,r)+2\times Q(l-1,r)+C_r^0\times 2^0Q(l,r+1)=Q(l,r)+2×Q(l−1,r)+Cr0×20
把刚才退出来的Q(l−1,r)Q(l-1,r)Q(l−1,r)的式子代进来得到
Q(l,r+1)=3×Q(l,r)−Crl×2l+Cr0×20Q(l,r+1)=3\times Q(l,r)-C_r^l\times 2^l+C_r^0\times 2^0Q(l,r+1)=3×Q(l,r)−Crl×2l+Cr0×20
利用这个式子可以推出r−1r-1r−1的情况:Q(l,r−1)=Q(l,r)+Cr−1l×2l−Cr0×203Q(l,r-1)=\frac{Q(l,r)+C_{r-1}^l\times 2^l-C_r^0\times 2^0}{3}Q(l,r−1)=3Q(l,r)+Cr−1l×2l−Cr0×20
那么就可以上莫队了。
trick:
注意能将rrr变大的时候尽量先移动rrr,否则先移动lll,避免转移经过非法组合数就gggggg了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline void outint(long long a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=100005;
cs int mod=19260817;
int fac[N],inv[N],ifac[N];
int pow2[N];
inline int C(int n,int m){
return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int l=1,r=1,now=1;
inline void ll(){now=(1ll*now-1ll*C(r,l)*pow2[l-1]%mod+mod)%mod;--l;}
inline void lr(){now=(1ll*now+1ll*C(r,l+1)*pow2[l]%mod)%mod;++l;}
inline void rl(){now=(1ll*now+1ll*C(r-1,l)*pow2[l]%mod-1ll*C(r,0)*pow2[0]%mod+mod)%mod*inv[3]%mod;--r;}
inline void rr(){now=(3ll*now-1ll*C(r,l)*pow2[l]%mod+1ll*C(r,0)*pow2[0]%mod+mod)%mod;++r;}
struct Query{int l,r,id;}Q[N];
int ans[N],block[N],B,bcnt;
inline bool cmp(cs Query &a,cs Query &b){
if(block[a.l]^block[b.l])return block[a.l]<block[b.l];
return (block[a.l]&1)^(a.r>b.r);
}
int n,m,q;
int maxn;
signed main(){
fac[0]=fac[1]=inv[0]=inv[1]=ifac[0]=ifac[1]=pow2[0]=1;
pow2[1]=2;
for(int re i=2;i<N;++i){
fac[i]=1ll*fac[i-1]*i%mod;
inv[i]=1ll*(mod-mod/i)*inv[mod-mod/i*i]%mod;
ifac[i]=1ll*ifac[i-1]*inv[i]%mod;
pow2[i]=(pow2[i-1]<<1)%mod;
}
q=getint();
for(int re i=1;i<=q;++i){
Q[i].id=i;
Q[i].r=getint();
Q[i].l=getint();
maxn=max(Q[i].r,maxn);
}
B=sqrt(maxn);bcnt=1;
for(int re i=1;i<=maxn;++i){
block[i]=bcnt;
if(i%B==0)++bcnt;
}
sort(Q+1,Q+q+1,cmp);
for(int re i=1;i<=q;++i){
if(Q[i].r>=r){
while(r<Q[i].r)rr();
while(r>Q[i].r)rl();
while(l<Q[i].l)lr();
while(l>Q[i].l)ll();
}
else{
while(l<Q[i].l)lr();
while(l>Q[i].l)ll();
while(r>Q[i].r)rl();
while(r<Q[i].r)rr();
}
ans[Q[i].id]=now;
}
for(int re i=1;i<=q;++i)outint(ans[i]),pc('\n');
return 0;
}