1 条题解
-
0
题解
题目给出了最终积分榜,其中胜利得 3 分、平局双方各得 1 分、失败得 0 分。设 支队伍的总积分之和为 ,则可以推算出胜场数 (相比全部平局多出的积分正好是胜场数),而平局场数 。因此我们只需统计所有满足这两个数字的比赛结果方案数。
按照队伍编号从小到大逐对填充比赛结果:枚举队伍 与更高编号的队伍 的对局,可以让 胜、 胜或双方打平。我们用
sx
、sy
记录剩余可用的胜场和和局场数,因此每次设定结果前都要判断是否还有额度。tmp[i]
表示当前为队伍 已经累积的积分,当 时说明队伍 已经和所有对手比完了,此时必须严格等于目标积分a[x]
,否则该分支无效。由于不同队伍积分相同会导致大量对称情况,需要在每次完成队伍 的所有比赛后,把剩余队伍的“还差多少分”排序,利用哈希表记忆化搜索以避免重复。这样整棵搜索树的状态数量可控,最终答案即为所有合法搜索路径的计数并对模数取值。代码中使用递归回溯配合记忆化,复杂度对 完全可行。
#include<bits/stdc++.h> #define maxn 12 #define mo 1000000007 #define lc 28 #define LL long long using namespace std; LL n,ans; LL a[maxn],tmp[maxn],sum[maxn]; LL sx,sy,s; 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; } for(LL i=x+1;i<=n;i++){ sum[i]=a[i]-tmp[i]; } sort(sum+x+1,sum+n+1); LL hah=0; for(LL i=x+1;i<=n;i++){ hah=hah*lc+sum[i]; } if(M.find(hah)!=M.end()){ return M[hah]; } return M[hah]=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%mo; } 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
- 3256
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者