考场上看到这个题的时候,我记得这个式子好像是不能化简的= =,所以我就开始想能不能从c(m,0)+c(m,1)+...+c(m,m)轻松推出c(n,0)+c(n,1)+c(n,2)....+c(n,m),因为前者就是2^m,如果能O(1)从m扩大到n就行了,结果发现从
c(m,0)+c(m,1)=sum1 (1)式
推到
c(m+1,0)+c(m+1,1)+..c(m+1,m)=sum2 (2)式
的规律
c(m+1,1)-c(m,1)=c(m,0),c(m+1,2)-c(m,2)=c(m,1),
所以从(1)式推到(2)就是 sum2=sum1+sum1-c(m,n)
然后看到T=1e5,n,m=1e5,突然就想到莫队,因为n加减1就用上面的公式O(1)转移,m加减1就用+c(n,m+1)或者-c(n,m),用lucas+预处理也可以O(1)转移。
打了6场多校,我队第一次做出了非签到题,感觉我很多次发挥都是想到莫队= =,上次湘潭也是莫队+二分树状数组A了一道主席树的题。。。
#include<bits/stdc++.h>
#define X first
#define Y second
#define pb push_back
#define mk make_pair
#define rep(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int MAXN = 100010;
const int mod = 1e9 + 7;
int T,sz;
struct node
{
int m,n,ind;
}a[maxn];
LL sum;
LL ans[maxn];
LL inv[MAXN + 10], fac[MAXN + 10];
void init()
{
inv[0] = fac[0] = inv[1] = fac[1] = 1;
for(int i = 1; i < MAXN; i++)
fac[i] = fac[i - 1] * i % mod;
for(int i = 2; i < MAXN; i++)
inv[i] = (mod - (mod / i)) * inv[mod % i] % mod;//lucas?????
for(int i = 1; i < MAXN; i++)
inv[i] = inv[i - 1] * inv[i] % mod;
}
inline LL C(int n, int m)//???? C n,m
{
if(n<m)return 0;
return (fac[n] * inv[m] % mod) * inv[n - m] %mod;
}
inline bool cmp(const node &x,const node &y)
{
if(x.m/sz==y.m/sz)
return x.n<y.n;
return x.m/sz<y.m/sz;
}
inline void prework()
{
scanf("%d",&T);
sz=sqrt(T);
for(int i=1;i<=T;i++)
scanf("%d%d",&a[i].n,&a[i].m),a[i].ind=i;
sort(a+1,a+1+T,cmp);
}
inline void mainwork()
{
int l=1,r=1;
sum=2;
for(int i=1;i<=T;i++)
{
while(r<a[i].n)
{
r++;
sum=(sum+(sum-C(r-1,l)+mod)%mod)%mod;
}
while(r>a[i].n)
{
sum=(1ll*((sum+C(r-1,l))%mod)*inv[2])%mod;
r--;
}
while(l<a[i].m)
{
sum=(sum+C(r,l+1))%mod;
l++;
}
while(l>a[i].m)
{
l--;
sum=(sum-C(r,l+1)+mod)%mod;
}
ans[a[i].ind]=sum;
}
}
inline void print()
{
for(int i=1;i<=T;i++)
printf("%lld\n",ans[i]);
}
int main()
{
init();
prework();
mainwork();
print();
return 0;
}