AGC001E 代数解法

$\text{Description}$

计算:

对 $10^9+7$ 取模,$n\le 2\times 10^5$,$a_i,b_i\le 2000$。

$\text{Solution}$

组合意义没有精神!!我们代数解法才是你们的老大哥!!

题目等价于求:

其中 $t_i=a_i+b_i$。

我们希望将 $i$ 与 $j$ 拆开,那么只需利用范德蒙德卷积:

显然可以交换求和次序,然后记

则原式化为:

问题转为求解 $F(k)$。

直接计算是 $O(nk)$ 的,略去不提。

考察数列:

不妨将 $T_i(k)$ 看作二维平面的一个点 $(t_i,a_i+k)$,该点会给 $F(k)$ 贡献 $T_i(k)$,容易发现 $T_i$ 构成了垂直 $x$ 轴于 $(t_i,0)$ 且高为 $t_i$ 的线段。

观察 $x=x_0$ 上的线段,它们的高度是一致的,只是贡献区间平移了(这取决于 $a$ 的值)。

现在问题转化为,有一个初始全为 $0$ 的模板序列,$q$ 次修改,第 $i$ 次修改给出一个修改序列和一个区间 $[l_i,r_i]$,要求把修改序列合并到模板序列的对应区间上,最后求模板序列。

当然,修改序列还有个特点,它是:

那么我们将这些东西看作是对 OGF 的修改,再次进行转化。

首先让原来的这个东西整体向右平移一定单位 $S$,现在下标一定是非负的。

对于一个修改序列,我们发现它的 OGF 就是 $(1+x)^{t_i}$。那么我们要让它平移整体平移量与自身平移量,也就是 $S-a_i$。

为了方便,我们将问题转为计算:

或者说是计算:

使用秦九韶算法即可 $O(n+m^2)$ 解决,值得一提的是,我乱实现的屑代码目前领先其它所有洛谷提交。

$\text{Code}$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<bits/stdc++.h>
#define REG register
using namespace std;
typedef unsigned long long u64;
const int Mod=1e9+7,N=2e5+10,M=8e3,S=4e3;
inline void read(int& x){
static char c;
while(!isdigit(c=getchar()));x=c^48;
while(isdigit(c=getchar()))x=(x*10)+(c^48);
}

inline void Add(int& x,int y){(x+=y)>=Mod?x-=Mod:x;}
inline int Aod(int x){return x>=Mod?x-Mod:x;}
inline int Pow(int a,int b){
int res=1;
while(b){
if(b&1) res=(u64)res*a%Mod;
a=(u64)a*a%Mod,b>>=1;
}
return res;
}
inline int Rec(int a){return Pow(a,Mod-2);}


int n,Ans;
int A[N],B[N];
int Fac[M+10],Iac[M+10];

inline void Init(){
Fac[0]=Iac[0]=1;
for(REG int i=1;i<=M;++i) Fac[i]=(u64)Fac[i-1]*i%Mod;
Iac[M]=Rec(Fac[M]);
for(REG int i=M-1;i;--i) Iac[i]=(u64)Iac[i+1]*(i+1)%Mod;
}

inline int Ask(int a,int b){
if(b<0||a<b) return 0;
return (u64)Fac[a]*Iac[b]%Mod*Iac[a-b]%Mod;
}

int F[M+10],G[M+10];
inline void Mul_1_x(){G[0]=F[0];for(REG int i=1;i<=M;++i)G[i]=F[i],Add(F[i],G[i-1]);}

vector<int> V[S+10];

inline void Work(){
read(n);
for(REG int i=1;i<=n;++i) read(A[i]),read(B[i]),B[i]+=A[i],V[B[i]].push_back(S-A[i]);
Init();
for(REG int i=S;i;--i){
for(int v:V[i]) Add(F[v],1);
Mul_1_x();
}
for(REG int i=-S;i<=S;++i) Add(Ans,(int)((u64)F[S+i]*F[S-i]%Mod));
for(REG int i=1;i<=n;++i) Add(Ans,Mod-Ask(2*B[i],2*A[i]));
Ans=(u64)Ans*Rec(2)%Mod;
printf("%d\n",Ans);
}

int main(){Work();}
#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×