题目链接;
SGU 476 Coach’s Trouble
题意:
给一个
n
,代表
数据范围:
分析:
我们先考虑
3∗n
个人,没有限制条件时的方案数
f[n]
,根据排列组合的知识我们可以得到:
f[n]=∏i<=n−1i=0C33∗(n−i)Ann
化简一下得到递推式:
f[n]=(3n−1)(3n−2)2∗f[n−1]
考虑到数据范围需要用大数。
然后我们来考虑 k 个限制条件。
如果只考虑一个限制条件,那么每个限制条件把限制条件用上后就相当与刚刚多算了
如果考虑两个限制条件,那么这两个限制条件必须是彼此独立的,也就是两个集合没有交集,然后根据容斥原理,这时候就要加上 f]n−2]
依次递推。。。
因为 k 最大值为
我们可以记录当前已经搜索 [1,3∗n] 中的哪些编号,然后对于每个集合都要和这些编号不相交才能选择这个集合,选择这个集合后就要把这个集合的所有元素标记上进行 dfs ,这样起到了剪枝的作用。
另外这题的 Test 13 有毒啊。。。。。。。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 1005;
const int SIZE = 11000;
struct BigInteger {
int len, s[SIZE + 5];
BigInteger () {
memset(s, 0, sizeof(s));
len = 1;
}
BigInteger operator = (const char *num) { //字符串赋值
memset(s, 0, sizeof(s));
len = strlen(num);
for(int i = 0; i < len; i++) s[i] = num[len - i - 1] - '0';
return *this;
}
BigInteger operator = (const int num) { //int 赋值
memset(s, 0, sizeof(s));
char ss[SIZE + 5];
sprintf(ss, "%d", num);
*this = ss;
return *this;
}
BigInteger (int num) {
*this = num;
}
BigInteger (char* num) {
*this = num;
}
string str() const { //转化成string
string res = "";
for(int i = 0; i < len; i++) res = (char)(s[i] + '0') + res;
if(res == "") res = "0";
return res;
}
BigInteger clean() {
while(len > 1 && !s[len - 1]) len--;
return *this;
}
BigInteger operator + (const BigInteger& b) const {
BigInteger c;
c.len = 0;
for(int i = 0, g = 0; g || i < max(len, b.len); i++) {
int x = g;
if(i < len) x += s[i];
if(i < b.len) x += b.s[i];
c.s[c.len++] = x % 10;
g = x / 10;
}
return c.clean();
}
BigInteger operator - (const BigInteger& b) {
BigInteger c;
c.len = 0;
for(int i = 0, g = 0; i < len; i++) {
int x = s[i] - g;
if(i < b.len) x -= b.s[i];
if(x >= 0) g = 0;
else {
g = 1;
x += 10;
}
c.s[c.len++] = x;
}
return c.clean();
}
BigInteger operator * (const int num) const {
int c = 0, t;
BigInteger pro;
for(int i = 0; i < len; ++i) {
t = s[i] * num + c;
pro.s[i] = t % 10;
c = t / 10;
}
pro.len = len;
while(c != 0) {
pro.s[pro.len++] = c % 10;
c /= 10;
}
return pro.clean();
}
BigInteger operator * (const BigInteger& b) const {
BigInteger c;
for(int i = 0; i < len; i++) {
for(int j = 0; j < b.len; j++) {
c.s[i + j] += s[i] * b.s[j];
c.s[i + j + 1] += c.s[i + j] / 10;
c.s[i + j] %= 10;
}
}
c.len = len + b.len + 1;
return c.clean();
}
BigInteger operator / (const BigInteger &b) const {
BigInteger c, f;
for(int i = len - 1; i >= 0; --i) {
f = f * 10;
f.s[0] = s[i];
while(f >= b) {
f = f - b;
++c.s[i];
}
}
c.len = len;
return c.clean();
}
//高精度取模
BigInteger operator % (const BigInteger &b) const{
BigInteger r;
for(int i = len - 1; i >= 0; --i) {
r = r * 10;
r.s[0] = s[i];
while(r >= b) r = r - b;
}
r.len = len;
return r.clean();
}
bool operator < (const BigInteger& b) const {
if(len != b.len) return len < b.len;
for(int i = len - 1; i >= 0; i--)
if(s[i] != b.s[i]) return s[i] < b.s[i];
return false;
}
bool operator > (const BigInteger& b) const {
return b < *this;
}
bool operator <= (const BigInteger& b) const {
return !(b < *this);
}
bool operator == (const BigInteger& b) const {
return !(b < *this) && !(*this < b);
}
bool operator != (const BigInteger &b) const {
return !(*this == b);
}
bool operator >= (const BigInteger &b) const {
return *this > b || *this == b;
}
friend istream & operator >> (istream &in, BigInteger& x) {
string s;
in >> s;
x = s.c_str();
return in;
}
friend ostream & operator << (ostream &out, const BigInteger& x) {
out << x.str();
return out;
}
};
BigInteger f[MAX_N];
void init()
{
f[0] = f[1] = 1;
for(int i = 2; i < MAX_N; ++i) {
f[i] = f[i - 1] * ((3 * i - 1) * (3 * i - 2) / 2);
}
}
int num[25], vis[4010], data[25][5];
void dfs(int cur, int total, int limit)
{
num[total]++;
for(int i = cur; i < limit; ++i) {
int flag = 0;
if(vis[data[i][0]] == 0 && vis[data[i][1]] == 0 && vis[data[i][2]] == 0) {
flag = 1;
}
if(flag == 0) continue;
for(int j = 0; j < 3; ++j) { vis[data[i][j]] = 1; }
dfs(i + 1, total + 1, limit);
for(int j = 0; j < 3; ++j) { vis[data[i][j]] = 0; }
}
}
int main()
{
init();
int n, k;
while(cin >> n >> k) {
for(int i = 0; i < k; ++i) {
cin >> data[i][0] >> data[i][1] >> data[i][2];
}
BigInteger ans = 0;
memset(vis, 0, sizeof(vis));
memset(num, 0, sizeof(num));
dfs(0, 0, k);
for(int i = 0; i <= min(k, n); i += 2) {
ans = ans + f[n - i] * num[i];
}
for(int i = 1; i <= min(k, n); i += 2) {
ans = ans - f[n - i] * num[i];
}
cout << ans.clean() << endl;
}
return 0;
}