SGU 476 Coach's Trouble(集合独立性、容斥、高精度)

来源:互联网 发布:js通过标签名获取元素 编辑:程序博客网 时间:2024/05/02 01:33

题目链接;
SGU 476 Coach’s Trouble
题意:
给一个n,代表3n个人的编号从13n,需要把这3n个人每三人一组分成三组,但是有k个限制条件:a[i],b[i],c[i]不能分在一组。问能分成的方案数是多少?k个限制条件是彼此不同的。
数据范围:1N1000,0K20
分析:
我们先考虑3n个人,没有限制条件时的方案数f[n],根据排列组合的知识我们可以得到:

f[n]=i<=n1i=0C33(ni)Ann

化简一下得到递推式:
f[n]=(3n1)(3n2)2f[n1]

考虑到数据范围需要用大数。
然后我们来考虑k个限制条件。
如果只考虑一个限制条件,那么每个限制条件把限制条件用上后就相当与刚刚多算了f[n1]中方案。
如果考虑两个限制条件,那么这两个限制条件必须是彼此独立的,也就是两个集合没有交集,然后根据容斥原理,这时候就要加上f]n2]
依次递推。。。
因为k最大值为20,所以最坏的时间复杂度是2020220,对于题目限制500ms是不行的,需要优化。
我们可以记录当前已经搜索[1,3n]中的哪些编号,然后对于每个集合都要和这些编号不相交才能选择这个集合,选择这个集合后就要把这个集合的所有元素标记上进行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;}
0 0
原创粉丝点击