呦,来一次久违的BBQ吧!
AT题...日本的题库质量一向很高
这题是有关组合数的DP...
#include<bits/stdc++.h>
#define rap(i,first,last) for(int i=first;i<=last;++i)
using namespace std;
const int maxN=2005;
const int mod=1e9+7;
const int inv2=500000004;//预处理2的逆元
long long fac[maxN*4+100],inv[maxN*4+100];
long long dp[maxN*2+100][maxN*2+100],N;
int A[1000005],B[1000005];
long long C(int n,int m)//计算组合数
{
return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
//预处理组合数
fac[0]=inv[0]=inv[1]=1;
rap(i,1,maxN*4)fac[i]=1ll*fac[i-1]*i%mod;
rap(i,2,maxN*4)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
rap(i,1,maxN*4)inv[i]=1ll*inv[i-1]*inv[i]%mod;
scanf("%d",&N);
rap(i,1,N)
{
scanf("%d%d",&A[i],&B[i]);
dp[maxN-A[i]][maxN-B[i]]++;//在-A[i],-B[i]位置加一
}
rap(i,-maxN+1,maxN)
rap(j,-maxN+1,maxN)
{
dp[maxN+i][maxN+j]+=dp[maxN+i-1][maxN+j]+dp[maxN+i][maxN+j-1];//类似杨慧三角的DP
dp[maxN+i][maxN+j]%=mod;
}
long long answer=0;
rap(i,1,N)
{
answer+=dp[maxN+A[i]][maxN+B[i]];//对答案加上这个位置的方案数
answer%=mod;
answer-=C(A[i]*2+B[i]*2,A[i]*2);//减去自己到自己的方案数
answer=(answer+mod)%mod;
}
answer*=inv2;//可以发现多计算了一遍,需要除二,在膜域中也就是乘上2的逆元
answer%=mod;
printf("%lld\n",answer);//输出answer
return ~0;
}
看似一道简单的DP,其中涉及了各种方面的知识点只有对膜域和组合数的掌握才能在做这类题时得心应手.
原文:https://www.cnblogs.com/Sxy_Limit/p/12163755.html