ATG1E BBQ Hard 学习笔记
Luogu Link
题意简述
计算 $$\sum_{i=1}^n \sum_{j=i+1}^n \dbinom{a_i+b_i+a_j+b_j}{a_i+a_j}$$ 的值。答案对 \(10^9+7\) 取模。
\(N\le 2\times 10^5,a_i,b_i\le 2\times 10^3\)。
做法解析
\(O(N^2)\) 的做法是暴力枚举 \(i,j\),\(O(1)\) 计算出 \(\dbinom{a_i+b_i+a_j+b_j}{a_i+a_j}\),将结果全部相加即可。
怎么优化?我们不妨先考虑一下其组合意义。众所周知 \(\dbinom{x+y}{x}\) 的一个组合意义是:只往右或上走,从 \((0,0)\) 走到 \((x,y)\) 的方案数(相当于往 \(x\) 个向右走操作中插入 \(y\) 个向上走操作的方案数)。所以我们要求的东西就是从 \((0,0)\) 走到所有 \((a_i+a_j,b_i+b_j)\) 的方案数。这么做起点只有一个,却要一个个统计 \(O(N^2)\) 个终点的答案,太劣了。
考虑复杂度平衡。我们把网格图从 \(((0,0),(a_i+a_j,b_i+b_j))\) 平移到 \(((-a_i,-b_i),(a_j,b_j))\)。现在就变为了 \(O(N)\) 个起点,\(O(N)\) 个终点。我们 \(O(N)\) 地将每个起点的初始方案数加一,然后递推一遍组合数,最后 \(O(N)\) 收集每个终点的方案数。优异啊!
由于题目要求只统计 \(i<j\) 的方案数,所以要减去自己做起点到自己做重点的方案数,最后乘上 \(2\) 的逆元。这道题就做完了!
代码实现
#include <bits/stdc++.h>
using namespace std;
namespace obasic{typedef long long lolo;template <typename _T>void readi(_T &x){_T k=1;x=0;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')k=-1;for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';x*=k;return;}template <typename _T>void writi(_T x){if(x<0)putchar('-'),x=-x;if(x>9)writi(x/10);putchar(x%10+'0');}
};
using namespace obasic;
const int MaxN=2e5+5,MaxM=2e3+5,Mod=1e9+7,Df=2001;
int N;lolo A[MaxN],B[MaxN],facr[MaxM<<2],finv[MaxM<<2];
namespace omathe{lolo fastpow(lolo a,lolo b,lolo p){lolo res=1;for(;b;(a*=a)%=p,b>>=1)if(b&1)(res*=a)%=p;return res;}lolo getinv(lolo a,lolo p){return fastpow(a,p-2,p);}lolo Comb(lolo n,lolo m,lolo p){return facr[n]*finv[n-m]%p*finv[m]%p;}
};
using namespace omathe;
void prework(int n){facr[0]=finv[0]=1;for(int i=1;i<=n;i++)facr[i]=facr[i-1]*i%Mod;finv[n]=getinv(facr[n],Mod);for(int i=n-1;i;i--)finv[i]=finv[i+1]*(i+1)%Mod;
}
lolo C[MaxM<<1][MaxM<<1],ans;
int main(){readi(N);prework(Df*4+4);for(int i=1;i<=N;i++)readi(A[i]),readi(B[i]);for(int i=1;i<=N;i++)C[Df-A[i]][Df-B[i]]++;for(int i=1;i<=Df*2;i++){for(int j=1;j<=Df*2;j++){(C[i][j]+=(C[i-1][j]+C[i][j-1])%Mod)%=Mod;}}for(int i=1;i<=N;i++){(ans+=C[A[i]+Df][B[i]+Df])%=Mod;(ans+=Mod-Comb(A[i]*2+B[i]*2,A[i]*2,Mod))%=Mod;}(ans*=getinv(2,Mod))%=Mod;writi(ans);return 0;
}
反思总结
了解 \(\dbinom{x+y}{x}\) 的一个组合意义:只往右或上走,从 \((0,0)\) 走到 \((x,y)\) 的方案数。
熟练运用复杂度平衡思想,见到 \(O(1)-O(N^2)\) 的东西尝试平衡为 \(O(N)-O(N)\)。