@ysner
2018-07-25T09:07:14.000000Z
字数 1656
阅读 2416
搜索 记忆化
个球队,两两比赛,胜得分,平各得分。告知每队最后得分,询问有多少种不同比赛结果。
很有深意啊。反正这题不可能状压,那肯定是叫我们打记搜。
我一开始的想法是把搜索的状态设为各组当时的得分(爆不了)。
然而这样就不能记忆化了,因处理(加)得分时不知道两个队是否比赛过,强设该状态又炸空间。
于是还是枚举每场比赛的结果吧。
当然,可以有剪枝:
还有值得注意的一点,数组初始值应该设为,这样才能同已经计算过、方案数为的情况区分开来。
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<map>#define re register#define il inline#define ll long long#define max(a,b) ((a)>(b)?(a):(b))#define min(a,b) ((a)<(b)?(a):(b))#define fp(i,a,b) for(re int i=a;i<=b;i++)#define fq(i,a,b) for(re int i=a;i>=b;i--)using namespace std;const int mod=1e9+7;map<ll,ll>dp;ll n,pj,a[20];il ll gi(){re ll x=0,t=1;re char ch=getchar();while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();if(ch=='-') t=-1,ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();return x*t;}il bool cmp(re ll x,re ll y){return x>y;}il ll calc(re int x){re ll New=x,d[20];//!!!!fp(i,1,x) d[i]=a[i];sort(d+1,d+1+x);//!!!!!fp(i,1,x) New=New*28+d[i];//!!!!return New;}il ll dfs(re int l,re int r){re ll tot=0;if(a[r]>3*(r-l)) return -1;if(l==r)if(r==1) return 1;else{re ll now=calc(r-1);if(dp[now]) return dp[now];else return dp[now]=dfs(1,r-1);}if(a[l]>=3){a[l]-=3;re ll tmp=dfs(l+1,r);if(tmp!=-1) tot+=tmp;if(tot>=mod) tot-=mod;a[l]+=3;}if(a[r]>=3){a[r]-=3;re ll tmp=dfs(l+1,r);if(tmp!=-1) tot+=tmp;if(tot>=mod) tot-=mod;a[r]+=3;}if(a[l]&&a[r]){--a[l];--a[r];re ll tmp=dfs(l+1,r);if(tmp!=-1) tot+=tmp;if(tot>=mod) tot-=mod;++a[l];++a[r];}return tot?tot:-1;}int main(){n=gi();fp(i,1,n) a[i]=gi();sort(a+1,a+1+n,cmp);printf("%lld\n",dfs(1,n));return 0;}
