您的位置:首页 > 其它

【JZOJ 4924】 【NOIP2017提高组模拟12.17】向再见说再见

2016-12-17 21:07 513 查看

Description



Data Constraint



Solution

我们用dp来处理这道题。我们想将第一对的人从小到大排序,d[i]表示第二队有多少人的能力比第一队中第i人的能力低。设f[i][j]表示前i个人赢j场的方案数,但先不考虑第i个人被击败时被谁击败,只考虑赢的状况。那么f[i+1][j+1]+=f[i][j]*(d[i+1]-j),f[i+1][j]=f[i][j]。对于一个f
[i],我们现在将剩余的n-i个人任意分配对手,并不考虑输赢。那么显然有g[i]=f[n][i]∗(n−i)!,代表的含义是第一队至少赢i场的方案数。

再来考虑一下怎么去重。

对于当前的一个答案ans[i],显然它的g[i]中包含ans[i+1]~ans
的情况。那么我们对于一个答案ans[j] (j>i),我们要在他胜利的j场中挑出i场让他赢,其余的让他输,那么情况就是cij。所以ans[i]=g[i]−∑nj=i+1ans[j]∗cij。复杂度O(N2).

Code

#include<iostream>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=2005,mo=1e9+7;
ll f[maxn][maxn],a[maxn],b[maxn],d[maxn],g[maxn],p[maxn],c[maxn][maxn],ans[maxn];
ll n,m,i,t,j,k,l;
int main(){
//freopen("data.in","r",stdin);
scanf("%lld%lld",&n,&m);
if ((n+m)%2) printf("0\n");
else{
c[0][0]=1;
for (i=1;i<=n;i++){
for (j=1;j<=n;j++)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mo;
c[i][0]=1;
}
for (i=1;i<=n;i++)
scanf("%lld",&a[i]);
for (i=1;i<=n;i++)
scanf("%lld",&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+n+1);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (b[j]<a[i]) d[i]++;
f[0][0]=1;
for (i=0;i<n;i++)
for (j=0;j<=i;j++){
if (!f[i][j])continue;
f[i+1][j+1]=(f[i+1][j+1]+f[i][j]*(d[i+1]-j))%mo;
f[i+1][j]=(f[i+1][j]+f[i][j])%mo;
}
p[0]=1;
for (i=1;i<=n;i++)
p[i]=p[i-1]*i%mo;
for (i=0;i<=n;i++)
g[i]=f
[i]*p[n-i]%mo;
for (i=n;i>=1;i--){
ans[i]=g[i];
for (j=i+1;j<=n;j++)
ans[i]=(ans[i]-ans[j]*c[j][i]%mo+mo)%mo;
}
k=(n+m)/2;
if (n-k!=k) t=(ans[k]+ans[n-k])%mo;
else t=ans[k];
printf("%lld\n",t);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: