• 【HNOI2013】比赛


    题面

    题解

    (n leq 9 o)爆搜

    对每一场的结果进行搜索,最后进行(mathrm{check})

    然后会发现没有什么分

    搜索最重要的就是剪枝

    接下来就列出一些剪枝

    1. 搜索时,强制每个人的得分不超过总分

    2. 如果一个人赢了所有的比赛也达不到总分,就直接退出

    3. 设比赛的总分为(s\_all),分出胜负的有(sx)场,平局的有(sy)场,那么有:

      (egin{cases}3 imes sx+2 imes sy=sx\sx+sy=frac{n(n-1)}{2}end{cases})

      然后就可以解出(sx)(sy),然后就可以限制场数了。

    加上了这些剪枝之后,大概有(60)分,接下来就要想一些其他的优化。

    接下来我们发现人数为(s),得分集合为(A)的方案数是相同的。

    于是记忆化一下,hash就可以了

    代码

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #include<map>
    #define RG register
    #define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
    #define clear(x, y) memset(x, y, sizeof(x))
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while(ch != '-' && (!isdigit(ch))) ch = getchar();
    	if(ch == '-') w = -1, ch = getchar();
    	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int maxn(1010), Mod(1e9 + 7);
    const unsigned long long X(31);
    typedef unsigned long long ll;
    
    int n, a[maxn], s[maxn], r[maxn], all, p, q, ans;
    std::map<ll, ll> f; using std::sort;
    
    inline void add(int &x, const int &y) { x += y; if(x >= Mod) x -= Mod; }
    int dfs(int x, int y)
    {
    	int ans = 0;
    	if(x == n) return 1;
    	if(a[x] + 3 * (n - y + 1) < s[x]) return 0;
    	if(y > n)
    	{
    		for(RG int i = x + 1; i <= n; i++) r[i] = s[i] - a[i];
    		sort(r + x + 1, r + n + 1);
    		ll ha = 0;
    		for(RG int i = x + 1; i <= n; i++) ha = ha * X + r[i];
    		if(f.find(ha) != f.end()) return f[ha];
    		else return f[ha] = dfs(x + 1, x + 2);
    	}
    
    	if(a[x] + 3 <= s[x] && p)
    		a[x] += 3, --p, add(ans, dfs(x, y + 1)), a[x] -= 3, ++p;
    	if(a[x] + 1 <= s[x] && a[y] + 1 <= s[y] && q)
    		++a[x], ++a[y], --q, add(ans, dfs(x, y + 1)), --a[x], --a[y], ++q;
    	if(a[y] + 3 <= s[y] && p)
    		a[y] += 3, --p, add(ans, dfs(x, y + 1)), a[y] -= 3, ++p;
    	return ans;
    }
    
    int main()
    {
    	n = read();
    	for(RG int i = 1; i <= n; i++) all += (s[i] = read());
    	p = all - n * n + n; q = (all - 3 * p) >> 1;
    	sort(s + 1, s + n + 1, std::greater<int>());
    	printf("%d
    ", dfs(1, 2));
    	return 0;
    }
    
  • 相关阅读:
    《当程序员的那些狗日日子》(六)继续熬夜学习的日子
    《当程序员的那些狗日日子》(四)喘过气来了
    《当程序员的那些狗日日子》(二)走上不归路
    《当程序员的那些狗日日子》(八)床上等你
    《当程序员的那些狗日日子》(一)毕业后的徘徊
    wince定时拍照功能(转)
    Excel公式找出某一列中是否有某值
    2010年到10月的流水帐
    不错的windows phone的博客
    将同一个表中的一个域更新到另外一个域的SQL文
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10396250.html
Copyright © 2020-2023  润新知