HDU

HDU - 5735

感觉还是对容斥不够熟悉啊。。

先用轮廓线dp求出f[ i ][ j ]表示 i 行 j 列 没有限制的方案数。

然后2^m枚举列的划分情况进行容斥。

对于每一种情况

t[ i ] 表示这种情况下, i 行没有限制的方案数。

g[ i ]表示这种情况下, i 行并且没有可以划分的行的方案数。

g[ i ] 可以从 t[ i ] 推过来。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = (int)1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int f[17][17] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
{0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597},
{0, 0, 3, 0, 11, 0, 41, 0, 153, 0, 571, 0, 2131, 0, 7953, 0, 29681},
{0, 1, 5, 11, 36, 95, 281, 781, 2245, 6336, 18061, 51205, 145601, 413351, 1174500, 3335651, 9475901},
{0, 0, 8, 0, 95, 0, 1183, 0, 14824, 0, 185921, 0, 2332097, 0, 29253160, 0, 366944287},
{0, 1, 13, 41, 281, 1183, 6728, 31529, 167089, 817991, 4213133, 21001799, 106912793, 536948224, 720246619, 704300462, 289288426},
{0, 0, 21, 0, 781, 0, 31529, 0, 1292697, 0, 53175517, 0, 188978103, 0, 124166811, 0, 708175999},
{0, 1, 34, 153, 2245, 14824, 167089, 1292697, 12988816, 108435745, 31151234, 940739768, 741005255, 164248716, 498190405, 200052235, 282756494},
{0, 0, 55, 0, 6336, 0, 817991, 0, 108435745, 0, 479521663, 0, 528655152, 0, 764896039, 0, 416579196},
{0, 1, 89, 571, 18061, 185921, 4213133, 53175517, 31151234, 479521663, 584044562, 472546535, 732130620, 186229290, 274787842, 732073997, 320338127},
{0, 0, 144, 0, 51205, 0, 21001799, 0, 940739768, 0, 472546535, 0, 177126748, 0, 513673802, 0, 881924366},
{0, 1, 233, 2131, 145601, 2332097, 106912793, 188978103, 741005255, 528655152, 732130620, 177126748, 150536661, 389322891, 371114062, 65334618, 119004311},
{0, 0, 377, 0, 413351, 0, 536948224, 0, 164248716, 0, 186229290, 0, 389322891, 0, 351258337, 0, 144590622},
{0, 1, 610, 7953, 1174500, 29253160, 720246619, 124166811, 498190405, 764896039, 274787842, 513673802, 371114062, 351258337, 722065660, 236847118, 451896972},
{0, 0, 987, 0, 3335651, 0, 704300462, 0, 200052235, 0, 732073997, 0, 65334618, 0, 236847118, 0, 974417347},
{0, 1, 1597, 29681, 9475901, 366944287, 289288426, 708175999, 282756494, 416579196, 320338127, 881924366, 119004311, 144590622, 451896972, 974417347, 378503901}
};

int n, m;
int g[N], t[N];
vector<int> V;

int main() {
    while(scanf("%d%d", &n, &m) != EOF) {
        int ans = 0;
        for(int mask = 0; mask < (1 << m - 1); mask++) {
            int op = 1;
            V.clear();
            int last = 0;
            for(int j = 0; j < m - 1; j++) {
                if(mask >> j & 1) {
                    V.push_back(j + 1 - last);
                    last = j + 1;
                    op = -op;
                }
            }
            V.push_back(m - last);
            for(int i = 1; i <= n; i++) {
                t[i] = 1;
                for(auto &b : V) {
                    t[i] = 1LL * t[i] * f[i][b] % mod;
                }
            }
            g[1] = t[1];
            for(int i = 2; i <= n; i++) {
                g[i] = t[i];
                for(int j = 1; j < i; j++) {
                    sub(g[i], 1LL * g[j] * t[i - j] % mod);
                }
            }
            if(op > 0) add(ans, g[n]);
            else sub(ans, g[n]);
        }
        printf("%d
", ans);
    }
    return 0;
}

/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/11544363.html