[bzoj3139][搜索][哈希]比赛

版权声明:蒻蒟的bolg... https://blog.csdn.net/Rose_max/article/details/85246320

Description

沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛。此次联 赛共N支球队参加,比赛规则如下: (1)
每两支球队之间踢一场比赛。 (2) 若平局,两支球队各得1分。 (3) 否则胜利的球队得3分,败者不得分。
尽管非常遗憾没有观赏到精彩的比赛,但沫沫通过新闻知道了每只球队的最后总得分, 然后聪明的她想计算出有多少种可能的比赛过程。
譬如有3支球队,每支球队最后均积3分,那么有两种可能的情况: 可能性1 可能性2 球队 A B C 得分 球队 A
B C 得分 A - 3 0 3 A - 0 3 3 B 0

  • 3 3 B 3 - 0 3 C 3 0 - 3 C 0 3 - 3 但沫沫发现当球队较多时,计算工作量将非常大,所以这个任务就交给你了。请你计算
    出可能的比赛过程的数目,由于答案可能很大,你只需要输出答案对109+7取模的结果

Input

第一行是一个正整数N,表示一共有N支球队。 接下来一行N个非负整数,依次表示各队的最后总得分。

输入保证20%的数据满足N≤4,40%的数据满足N≤6,60%的数据满足N≤8,100%的数据 满足3≤N≤10且至少存在一组解。

Output

仅包含一个整数,表示答案对10^9+7取模的结果

Sample Input

4

4 3 6 4

Sample Output

3

题解

搜索求方案,操作美如画
从头开始搜每场比赛结果
然后可以获得30分的好成绩
可行性剪枝优化一下
大概就是已经爆掉和全赢也到不了
然后一点柿子
决出胜负的场次设为 q 1 q1 ,平的场次设为 q 2 q2 ,总分数为 s u m sum
于是有 q 1 + q 2 = n ( n 1 ) 2 q1+q2=\frac{n*(n-1)}{2}
以及 3 q 1 + 2 q 2 = s u m 3q1+2q2=sum
根据这个可以剪掉胜负场次的胡乱搜
搜完一个人的时候,剩下人还差的分数可以用一个哈希存起来
显然剩下人怎么搞和之前的人没有关系
记忆化一下就过了.

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
#define ULL unsigned long long
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(int x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int mod=1e9+7;
const LL base=28;

map<LL,int> mp1,mp2;
int a[25],b[15],c[15],sum[15],Q[15],n;
LL ge(int u,int nw)
{
	LL ret=nw;
	for(int i=u;i<=n;i++)c[i]=Q[i]-sum[i];
	sort(c+u,c+1+n);
	for(int i=u;i<=n;i++)ret=ret*base+c[i];
	return ret;
}
int cnt1,cnt2;
LL dfs(int u,int v,int nw)
{
	if(sum[u]>Q[u])return 0;
	if(sum[u]+(n-v+1)*3<Q[u])return 0;
	if(v==n+1)
	{
		if(sum[u]!=Q[u])return 0;
		if(u==n)return 1;
		LL num=ge(u+1,nw);
		if(mp2[num])return mp1[num];mp2[num]=1;
		return mp1[num]=dfs(u+1,u+2,nw+1);
	}
	LL ret=0;
	if(4*(a[u]+1)<=Q[u]+n-1&&sum[u]+3<=Q[u]&&cnt1)
	{
		a[u]++;sum[u]+=3;cnt1--;
		(ret+=dfs(u,v+1,nw+1))%=mod;
		a[u]--;sum[u]-=3;cnt1++;
	}
	if(4*(a[v]+1)<=Q[v]+n-1&&sum[v]+3<=Q[v]&&cnt1)
	{
		a[v]++;sum[v]+=3;cnt1--;
		(ret+=dfs(u,v+1,nw+1))%=mod;
		a[v]--;sum[v]-=3;cnt1++;
	}
	if(2*b[u]<=3*n-3-Q[u]&&2*b[v]<=3*n-3-Q[v]&&sum[v]+1<=Q[v]&&sum[u]+1<=Q[u]&&cnt2)
	{
		b[u]++;b[v]++;sum[u]++;sum[v]++;cnt2--;
		(ret+=dfs(u,v+1,nw+1))%=mod;
		b[u]--;b[v]--;sum[u]--;sum[v]--;cnt2++;
	}
	return ret;	
}
int main()
{
	n=read();
	int su=0;
	for(int i=1;i<=n;i++)
	{
		Q[i]=read();
		su+=Q[i];
	}
	sort(Q+1,Q+1+n);
	cnt1=su-n*(n-1);
	cnt2=(su-3*cnt1)/2;
	pr2(dfs(1,2,0));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/85246320
今日推荐