[AGC001E] BBQ Hard
ImmortalWatcher · · 题解
大佬口中所说的经典题。
组合意义天地灭,代数推导保平安。
考虑先将题目柿子的限制弄小一点。
然后大力推导。
发现最后一个柿子可以用秦九韶算法快速计算,卷积暴力卷即可。
然后回到原题,修一修边界即可。
时间复杂度
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=8000,c=4000;
const int mo=1e9+7;
int n,a[200010],b[200010],fac[8010],inv[8010],ans,Ans[8010],mx;
vector<int> Q[8010];
inline int ksm(int x,int y)
{
int ret=1;
for (;y;y>>=1)
{
if (y&1) ret=1ll*ret*x%mo;
x=1ll*x*x%mo;
}
return ret;
}
inline int C(int x,int y){return 1ll*fac[x]*inv[y]%mo*inv[x-y]%mo;}
void mul()
{
for (int i=N;i>=1;i--)
Ans[i]=(Ans[i]+Ans[i-1])%mo;
}
int main()
{
fac[0]=1;inv[0]=1;
for (int i=1;i<=N;i++) fac[i]=1ll*fac[i-1]*i%mo;
inv[N]=ksm(fac[N],mo-2);
for (int i=N-1;i>=1;i--) inv[i]=1ll*inv[i+1]*(i+1)%mo;
scanf("%lld",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
Q[a[i]+b[i]].push_back(-a[i]+c);
mx=max(mx,a[i]+b[i]);
}
for (int i=c;i;i--)
{
for(auto v:Q[i])
Ans[v]=(Ans[v]+1)%mo;
mul();
}
for (int i=-c;i<=c;i++)
ans=(ans+1ll*Ans[c-i]*Ans[c+i]%mo)%mo;
for (int i=1;i<=n;i++)
ans=(ans-C(2*a[i]+2*b[i],2*a[i])%mo+mo)%mo;
ans=1ll*ans*inv[2]%mo;
printf("%lld\n",ans);
return 0;
}