传送门
解析:
总是忍不住要吐槽一句,这题面也太长了吧。。。
首先,肯定要把我们要求的东西推成一个式子,不然怎么可能做题。。。
设
f
i
f_i
fi表示当前以
i
i
i为最大值的方案数。
那么
i
i
i之后的数显然是单调递减且连续,方案数为
1
1
1。
考虑前
i
−
1
i-1
i−1个位置,放法数就是
∑
j
=
1
i
−
1
f
j
\sum_{j=1}^{i-1}f_j
∑j=1i−1fj
所以我们现在得到递推式
f
i
=
∑
j
=
1
i
−
1
f
j
f_i=\sum_{j=1}^{i-1}f_j
fi=∑j=1i−1fj,
f
1
=
1
f_1=1
f1=1。
转换一下 f i = ∑ j = 1 i − 1 f j = ∑ j = 1 i − 2 f j + f i − 1 = 2 f i − 1 f_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
所以得到通项公式 f i = 2 i − 1 f_i=2^{i-1} fi=2i−1
那么询问的答案就是
Q
(
n
,
m
)
=
∑
i
=
1
n
C
m
i
×
2
i
−
1
Q(n,m)=\sum_{i=1}^{n}C_{m}^i\times 2^{i-1}
Q(n,m)=∑i=1nCmi×2i−1
数据范围
1
e
5
1e5
1e5,果断莫队。
令
l
=
n
,
r
=
m
l=n,r=m
l=n,r=m
我们只需要找到根据
l
,
r
l,r
l,r更新答案的较小复杂度方法就行了
幸运的是,这个式子在
l
±
1
l\pm 1
l±1和
r
±
1
r \pm 1
r±1的时候都有
O
(
1
)
O(1)
O(1)的转移方式。
首先
l
l
l的转移:
Q
(
l
−
1
,
r
)
=
Q
(
l
,
r
)
−
C
r
l
×
2
l
−
1
Q(l-1,r)=Q(l,r)-C_r^l\times 2^{l-1}
Q(l−1,r)=Q(l,r)−Crl×2l−1
Q
(
l
+
1
,
r
)
=
Q
(
l
,
r
)
+
C
r
l
+
1
×
2
l
Q(l+1,r)=Q(l,r)+C_r^{l+1}\times 2^{l}
Q(l+1,r)=Q(l,r)+Crl+1×2l
这个转移十分显然,就是直接根据表达式转移。
而
r
r
r的转移需要一点技巧:
怎么求
Q
(
l
,
r
+
1
)
=
∑
i
=
1
l
C
r
+
1
i
×
2
i
−
1
Q(l,r+1)=\sum_{i=1}^lC_{r+1}^{i}\times 2^{i-1}
Q(l,r+1)=∑i=1lCr+1i×2i−1
由于帕斯卡三角形上的组合数递推公式 C n + 1 m = C n m + C n m − 1 C_{n+1}^m=C_n^m+C_n^{m-1} Cn+1m=Cnm+Cnm−1。我们把上面这个式子拆开得到 ∑ i = 1 l ( C r i + C r i − 1 ) × 2 i − 1 = ∑ i = 1 l C r i × 2 i − 1 + 2 × ∑ i = 1 l − 1 C r i × 2 i − 1 + C r 0 × 2 0 \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^0 i=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
)
+
C
r
0
×
2
0
Q(l,r+1)=Q(l,r)+2\times Q(l-1,r)+C_r^0\times 2^0
Q(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
)
−
C
r
l
×
2
l
+
C
r
0
×
2
0
Q(l,r+1)=3\times Q(l,r)-C_r^l\times 2^l+C_r^0\times 2^0
Q(l,r+1)=3×Q(l,r)−Crl×2l+Cr0×20
利用这个式子可以推出
r
−
1
r-1
r−1的情况:
Q
(
l
,
r
−
1
)
=
Q
(
l
,
r
)
+
C
r
−
1
l
×
2
l
−
C
r
0
×
2
0
3
Q(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:
注意能将 r r r变大的时候尽量先移动 r r r,否则先移动 l l l,避免转移经过非法组合数就 g g gg gg了。
代码:
#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;
}