[CQOI2009] 循环赛

(n) 支队伍比赛,每两支队伍比赛一次。若两支队伍打平,则各得到 (1) 分;否则,胜利的队伍得到 (3) 分,被打败的队伍得到 (0) 分。给出队伍的最终得分,求有多少种可能的分数表。

Solution

大力搜索+剪枝

先枚举 1v2,1v3,...,1vN,再枚举 2v3,2v4,...,2vN,以此类推

为了加速将所有人按照总分从小到大排序

然后利用 hash 记忆化一下

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 10;
const int mod = 11451419198107;
int a[N],n;
map<int,int> h;

int gethash(int i,int j) {
    int res = i*17+j;
    for(int i=1;i<=n;i++) ((res*=17)+=a[i])%=mod;
    return (res+mod)%mod;
}

int dfs(int i,int j) {
    if(a[i]<0) return 0;
    if(j>n) {
        if(a[i]) return 0;
        ++i, j=i+1;
    }
    if(h.find(gethash(i,j))!=h.end()) {
        return h[gethash(i,j)];
    }
    int tmp=0;
    if(i==n && a[i]==0) ++tmp;
    else {
        if(a[i]>0 && a[j]>0) {
            --a[i]; --a[j];
            tmp += dfs(i,j+1);
            ++a[i]; ++a[j];
        }
        if(a[i]>2) {
            a[i]-=3;
            tmp += dfs(i,j+1);
            a[i]+=3;
        }
        if(a[j]>2) {
            a[j]-=3;
            tmp += dfs(i,j+1);
            a[j]+=3;
        }
    }
    h[gethash(i,j)]=tmp;
    return tmp;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    cout<<dfs(1,2)<<endl;
}

原文地址:https://www.cnblogs.com/mollnn/p/12640666.html