题目来源:http://community.topcoder.com/stat?c=problem_statement&pm=12954
参考:http://apps.topcoder.com/wiki/display/tc/SRM+605
这题目有点难,关键是dp状态的选择不好想,在实现上用了 C++ STL中的set 和 map,效率不是很高,可以考虑用 bitmask 提高效率。
代码如下:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <stack>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <cstring>
using namespace std;
/*************** Program Begin **********************/
typedef set <int> seti;
const int MOD = 1000000007;
class AlienAndSetDiv2 {
public:
int N, K;
map <seti, int> dp[105];
int calc(int n, seti unmatched)
{
int res = 0;
map <seti, int>::iterator it;
it = dp[n].find(unmatched);
if (it != dp[n].end()) {
return dp[n][unmatched] % MOD;
}
if (n == 2 * N + 1) {
if (unmatched.size() == 0) {
res = 1;
}
} else {
seti newset;
if (unmatched.size() == 0) {
newset = unmatched;
newset.insert(n);
res += ( 2 * calc(n+1, newset) ) % MOD;
} else {
newset = unmatched;
int m = *newset.begin();
newset.erase(newset.begin());
res += calc(n+1, newset);
res %= MOD;
if (m != n - K) {
newset = unmatched;
newset.insert(n);
res += calc(n+1, newset);
res %= MOD;
}
}
}
dp[n][unmatched] = res;
return res;
}
int getNumber(int N, int K) {
this->N = N;
this->K = K;
int res = 0;
seti unmatched;
res = calc(1, unmatched);
return res;
}
};
/************** Program End ************************/
使用 bitmask 方法优化,代替 set。最坏情况由原来的220ms 提高到了6ms。
注意:位操作符的优先级要注意,很容易出错,最好都加上括号。
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <stack>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <cstring>
using namespace std;
/*************** Program Begin **********************/
const int MOD = 1000000007;
const int MAX_N = 50;
const int MAX_K = 10;
int dp[2 * MAX_N + 2][1 << MAX_K];
class AlienAndSetDiv2 {
public:
int N, K;
int calc(int n, int unmatched)
{
int res = 0;
if (-1 != dp[n][unmatched]) {
return dp[n][unmatched];
}
if (n == 2 * N + 1) {
if (0 == unmatched) { // 匹配成功
res = 1;
}
} else {
if (0 == unmatched) {
res += ( 2 * calc(n + 1, 1) ) % MOD;
} else {
int newset = unmatched;
int i = 0;
for (i = 0; (newset & 0x80000000 ) == 0; newset = ( newset << 1 ), ++i) {
// 注意位操作的优先级,要加括号
}
int mx = 31 - i; // mx 为unmatched不为0的最高位
// match with largest:
res += calc(n + 1, (unmatched - (1 << mx)) << 1 ); // 注意操作符优先级,要加括号
res %= MOD;
if (mx != K - 1) {
newset = unmatched;
newset = ( (newset << 1) | 1 );
res += calc(n + 1, newset);
res %= MOD;
}
}
}
dp[n][unmatched] = res;
return res;
}
int getNumber(int N, int K) {
this->N = N;
this->K = K;
int res = 0;
memset(dp, -1, sizeof(dp));
res = calc(1, 0);
return res;
}
};
/************** Program End ************************/