标签:复杂 ace 转化 efi time c++ 问题 大数据 ==
一道比较好的组合题
给定 \(n\) 个点对,求:
\(n\le 2\times10^5 \ \ \ x_i,y_i \le 2000\)
暴力是不可能的对吧
我们发现一个 \(\binom{x+y}{x}\) 的几何含义是从 \((0,0)\) 到 \((x,y)\) 的路径条数
转化题意:
给定 \(n\) 个点 \((x_i,y_i)\),每个点可以拆成 \((x_i,y_i)\) 和 \((-x_i,-y_i)\)
求在第三象限内找一个点,再在第一象限内找一个点的不同的路径数
我们首先可以对这个坐标进行 \(dp\) ,求从底下向上的路径(其实就是杨辉的那个求法)
(这里需要注意一下坐标为负的问题,如果开大数据范围可能是要离散吗?博主并不是很清楚)
最后统计答案,要减去相同点的情况,即 \(\binom {x_i+x_+y_i+y_i}{x_i+x_i}\),然后除以 \(2\)
这里需要组合数
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k==‘-‘) f=-1;
while(isdigit(k)) res=res*10+k-‘0‘,k=getchar();
return res*f;
}
const int mod=1e9+7,N=4e3+100,M=2e5+10,s=2010;
int inv[M],fac[M];
int n,x[M],y[M],f[N][N];
inline void prework()
{
inv[0]=inv[1]=1; fac[0]=1;
for(int i=1;i<M;++i) fac[i]=fac[i-1]*i%mod;
for(int i=2;i<M;++i) inv[i]=mod-mod/i*inv[mod%i]%mod;
for(int i=1;i<M;++i) inv[i]*=inv[i-1],inv[i]%=mod;;
return ;
}
inline int C(int n,int m){return fac[n]*inv[n-m]%mod*inv[m]%mod; }
signed main()
{
prework(); n=read();
for(int i=1;i<=n;++i) x[i]=read(),y[i]=read(),f[s-x[i]][s-y[i]]++;
for(int i=1;i<=(s<<1);++i)
{
for(int j=1;j<=(s<<1);++j)
{
f[i][j]+=(f[i][j-1]+f[i-1][j])%mod; f[i][j]%=mod;
}
}
int ans=0;
for(int i=1;i<=n;++i)
{
ans+=f[s+x[i]][s+y[i]]; ans%=mod;
ans-=C((x[i]<<1)+(y[i]<<1),(x[i]<<1));
ans+=mod; ans%=mod;
}printf("%lld\n",ans*inv[2]%mod);
return 0;
}
}
signed main(){return yspm::main();}
把不可求的组合数转化到几何上面,换成路径统计的那种做法来因值域降低复杂度
最后:逆元累乘的时候记得取模
AtCoder1983 [AGC001E] BBQ Hard
标签:复杂 ace 转化 efi time c++ 问题 大数据 ==
原文地址:https://www.cnblogs.com/yspm/p/12749483.html