标签:多少 name max def int include bit 相似度 组合
沃老师在出比赛的题目时遇到麻烦啦!
遇到的麻烦如下:
现在沃老师手上有 2n 道题,题目编号由 1~2n,已知第 i 道题难度为 ai,这些题的难度还满足当 i<j 时 ai≤aj。现在沃老师想把这些题目分在两套比赛上,每套比赛会被分到 n 道题,每道题都会恰出现在其中一场比赛中。假设分配完后,第一套题难度第 i 小的题的难度为 ci (第 i 小是指不去重的的第 i 小,例如有四道题难度分别是 1,1,2,3 时,难度第 3 小的题是难度是 2),第二套题难度第 i 小的题为 di,沃老师定义两场比赛的难度相似度为 ∑ni=1|ci?di|,且沃老师希望分配完题目后,两场比赛的难度相似度尽可能的小。
看到这你可能会觉得这算什么麻烦,难度相似度的最小值不就是 ∑ni=1(a2i?a2i?1) 嘛?
是的,光是要使难度相似度最小并不构成沃老师的麻烦,但沃老师是个好奇宝宝,他还想知道,有多少种分配题目的方式,能使难度相似度最小呢?这个问题可能就没那么简单了。
于是沃老师就来拜托聪明的度熊帮他解决他心中的困惑,各位也帮忙算算吧。
请输出分配题目的方式数量除以 109+7 的余数。
两种分配方式 A 和 B 不同当且仅当存在某道题出现在 A 的第一套比赛中,却没有出现在 B 的第一套比赛中。举例来说,当 n=1 时,第一套比赛含有题目 1 第二套比赛含有题目 2 和 第一套比赛含有题目 2 第二套比赛含有题目 1 是不同的。
一个很好的引理: 最优解 对于 \(<=v-1\) 和\(<=v\) 的 个数绝对值差不超过1
然后我们就可以枚举分配然后DP
#include<bits/stdc++.h>
using namespace std;
#define maxnn 4000
#define mod 1000000007
#define ll long long
ll f[maxnn];
ll sum[maxnn];
ll dp[maxnn];
ll T,n;
ll a[maxnn];
ll num[maxnn];
ll ksm(int a,int b)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll C(int n,int m)
{
if(n==m||m==0) return 1;
ll A=1,B=1;
for(int i=0;i<m;i++)
{
B*=(i+1)%mod;
A=A*(n-i)%mod;
}
return A*ksm(B,mod-2);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
int up=n<<1;
for(int i=1;i<=up;i++){
scanf("%d",&a[i]);
num[i]=0;
}
for(int i=1;i<=up;i++) num[a[i]]++;
dp[0]=1;
ll sum=0;
for(int i=1;i<=up;i++){
if((sum&1)==0&&(num[i]&1)==0){
dp[i]=dp[i-1]*C(num[i],num[i]>>1)%mod;
}
else if((sum&1)==0&&(num[i]&1)==1){
dp[i]=dp[i-1]*C(num[i],num[i]>>1)*2%mod;
}
else if((sum&1)==1&&(num[i]&1)==1){
dp[i]=dp[i-1]*C(num[i],num[i]>>1)%mod;
}
else {
dp[i]=dp[i-1]*C(num[i],num[i]>>1)%mod;
if(num[i]){
dp[i]+=dp[i-1]*C(num[i],(num[i]-2)>>1)%mod;
dp[i]%=mod;
}
}
sum+=num[i];
}
printf("%lld\n",dp[up]);
}
return 0;
}
标签:多少 name max def int include bit 相似度 组合
原文地址:https://www.cnblogs.com/OIEREDSION/p/11434287.html