您的位置:首页 > 其它

sgu 544 Chess Championship

2013-11-22 22:47 330 查看
绝好的一道题目,以前没做到过,要不是队友想到这个dp,要我还真不会搞。

题意:现在有两个比赛队伍,每个队伍的个数都在500之内,现在两个队伍之间的能力不会重复,要全排列安排比赛,问存在多少种排列使得 A的得分减去B的得分为K,得分的定义是本队的能力值大于对面的那个人。

解法:刚开始模型很混乱,根本没法搞,最后的解法是这样的,将所有的能力值进行从小到大的排序,然后dp[pos][a][b]的定义就是现在进行到pos位,然后之前的A的得分为a,B的得分为b,然后这样就可以进行递推了,将很多很多种情况全部融合在这种dp中了,直接往后递推就可以,枚举当前这个数字到底是用还是不用,神奇的模型。

#include <stdio.h>
#include <iostream>
#include <memory.h>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

typedef pair<int,bool> PIB;
typedef long long LL;
#define maxn 510
#define mod 1000000009

int n ,k;
PIB xu[maxn << 1];
LL dp[2][maxn][maxn];

void read() {
	int x;
	for(int i = 0 ;i < n;i++) {
		scanf("%d",&x);
		xu[i] = make_pair(x, true);
	}
	for(int i = n;i < 2 * n;i++) {
		scanf("%d",&x);
		xu[i] = make_pair(x, false);
	}
	sort(xu , xu + 2 * n);
}

int solve() {
	int s1 = 0, s2 = 0;
	memset(dp, 0, sizeof(dp));
	dp[0][0][0] = 1;
	for(int i = 0 ;i < 2 * n;i++) {
		int now = i % 2;
		int to = 1 - now;
		for(int f = 0;f <= n; f++)
			for(int g = 0;g <= n;g++) {
				if(0 == dp[now][f][g])
					continue;
				int l1 = s1 - f - g;
				int l2 = s2 - f - g;
				dp[to][f][g] = (dp[now][f][g] + dp[to][f][g]) % mod;
				if(true == xu[i].second) {
					dp[to][f+1][g] = (dp[to][f+1][g] + dp[now][f][g] * l2) % mod;
				}
				else {
					dp[to][f][g+1] = (dp[to][f][g+1] + dp[now][f][g] * l1) % mod;
				}
			}
		if(true == xu[i].second)
			s1 ++;
		else
			s2 ++;
		memset(dp[now], 0, sizeof(dp[now])); 
	}

	int a = (n + k) / 2;
	int b = (n - k) / 2;
	return dp[0][a][b];
}

int main() {
	cin >> n >> k;
	read();
	if(1 == (n + k) % 2) {
		cout << "0" << endl;
		return 0;
	}
	cout << solve() << endl;
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: