1 条题解
-
0
首先这道题有一个加强版,该讲的也都在那边的题解有了。
这个题最直接的想法就是暴搜,先搜1v2,1v3……1vN,然后2v3……搜到结尾
很显然这样做只能拿部分分(好吧我不知道这样究竟能拿多少部分分)
剪枝:
1.注意到我们把1队的所有比赛搜完后才开始搜的2,然而此时如果1队的总分已经不与期望得分相同了,那么就可以直接返回0了(88pts)
2.知道总分和总场数,可以求出所有比赛中胜场和平场。搜索时超过这个值则返回0(92pts)
3.记忆化搜索,搜完某个人的所有场次后,如果后面所有队剩余分数从小到大排成的序列已经搜过了,那么可以直接返回上次搜到的值,这可以用Hash处理(100pts)
当然还有一些别的剪枝。比如说,如果某人接下来每场都赢也不能获得期望的分数,那么返回0
我本来以为前两个剪枝就可以AC这个题然而没有。所以最后这两个题都评上了紫题附上一个两边都能过的AC代码
#include<bits/stdc++.h> typedef long long LL; const LL maxn=12; const LL mod=1e9+7; const LL base=28; using namespace std; LL n,ans; LL a[maxn],tmp[maxn],cz[maxn]; LL sx,sy,s; ///sx是总胜场,sy是总平场 map<LL,LL> M; LL cmp(LL x,LL y) { return x>y; } LL dfs(LL x,LL y) { LL now=0; if(x>=n) return 1; if(y>n) { if(tmp[x]!=a[x]) return 0; ///处理Hash for(LL i=x+1;i<=n;i++) cz[i]=a[i]-tmp[i]; sort(cz+x+1,cz+n+1); LL hsh=0; for(LL i=x+1;i<=n;i++) hsh=hsh*base+cz[i]; if(M.find(hsh)!=M.end()) return M[hsh]; else return M[hsh]=dfs(x+1,x+2); } if(tmp[x]+3<=a[x] && sx) tmp[x]+=3,sx--,now+=dfs(x,y+1),tmp[x]-=3,sx++; if(tmp[y]+3<=a[y] && sx) tmp[y]+=3,sx--,now+=dfs(x,y+1),tmp[y]-=3,sx++; if(tmp[x]+1<=a[x] && tmp[y]+1<=a[y] && sy) tmp[x]+=1,tmp[y]+=1,sy--,now+=dfs(x,y+1),tmp[x]-=1,tmp[y]-=1,sy++; return now%mod; } int main() { scanf("%lld",&n); for(LL i=1;i<=n;i++) scanf("%lld",&a[i]),s+=a[i]; sx=s-n*n+n;sy=(n*n-n)/2-sx; ///这个在纸上解方程 sort(a+1,a+n+1,cmp); ///啊,从大到小也是很重要的 printf("%lld",dfs(1,2)); return 0; }
- 1
信息
- ID
- 2959
- 时间
- 800ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者