[hdu 6355] Fireflies

题意

在一个(n)维有限超立方体(((1, p_1), (1, p_2), ... , (1, p_n)))中,你可以在若干个位置放一只萤火虫。

萤火虫可以行动若干次,每一次从((x_1, x_2, x_3,...,x_n))走向((y_1, y_2, y_3,...,y_n)),都要满足:

1.起点和终点要在超立方体内;

2.(forall_i x_i le y_i)

3.((sum y_i - x_i) = 1)

求最开始最少放多少个,才能确保存在一种方案,对于每一个单位空间,至少用一只萤火虫遍历它。

题解

最优解的结构可以用Dilworth定理来分析。

Dilworth定理表明,最小链覆盖数等于最大反链数,也即选出一个集合,使得集合中的位置两两不可达,要最大化这个集合的大小。

Sperner定理表明,若要选择一个集合(S)的幂集的一个子集使得其中没有一个集合包含在另一个集合中,则这种子集的大小最大为(inom {|S|}{lfloor |S| / 2 floor})

则Sperner定理的一个推广)恰好能给出本问题的解:

选择(n)维坐标之和为(M = lfloor frac {1}{2} sum_{i = 1} ^ n (p_i + 1) floor)的位置即可达到最大的数量。

则现在问题转化为求(sum_{i = 1} ^ n x_i = M)(1 le x_i le p_i)的解的数量。

这是个经典问题,可以用容斥来做。

但考虑到(n le 32),不能直接容斥。

容易想到可能会用到meet-in-middle。但是如何用中途相遇法呢?

考虑到如果我们容斥时选出集合(S)代表(S)中的(x_i)都至少比(p_i)大,方案数就是

[max(0, inom{M - 1 - sum_{i in S} p_i}{n - 1}) ]

考虑到(n)很小,然后就有一个套路,将这个组合数看成下降幂形式,然后就成了(sum_{i in S} p_i)(n - 1)次多项式。那么我们可以先预处理出这个多项式的系数,然后在处理出每个集合(S)(sum_{i in S} p_i)(这里的(S)是折半枚举的),然后meet-in-middle的时候合并一下,用个前缀和优化就好了。

注意到如果(M - 1 - sum_{i in S}p_i < 0),不能用下降幂来算,这种情况方案数应该算作(0)(实际上在这个问题中(inom {n}{m})只要(n < m)就是(0))。处理时,可以用一个双指针来搞一搞这部分。

最终复杂度大概是(O(2 ^ {n / 2} n ^ 2))

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 40, mo = 1e9 + 7;
const int M = 1 << 16 | 5;
inline int read () {
    static int x;
    scanf("%d", &x);
    return x;
}
inline ll exp (ll a, ll b, ll ret = 1) {
    for (a %= mo; b; b >>= 1, a = a * a % mo)
        if (b & 1) ret = ret * a % mo;
    return ret;
}

int n, m, a[N];
int bitcnt[M];
ll k, cb[N][N], ivf[N];
ll f[N][N], coe[N];

void prework () {
    ivf[0] = 1;
    for (int i = 1; i < N; ++i)
        ivf[i] = ivf[i - 1] * exp(i, mo - 2) % mo;
    bitcnt[0] = 0;
    for (int i = 1; i < M; ++i)
        bitcnt[i] = bitcnt[i >> 1] + (i & 1);
    cb[0][0] = 1;
    for (int i = 1; i < N; ++i) {
        cb[i][0] = cb[i][i] = 1;
        for (int j = 1; j < i; ++j)
            cb[i][j] = (cb[i - 1][j - 1] + cb[i - 1][j]) % mo;
    }
}
void predo () {
    memset(f, 0, sizeof f);
    f[0][0] = n & 1 ? 1 : -1;
    for (int i = 1; i < n; ++i) {
        for (int j = 1; j < n; ++j)
            f[i][j] = f[i - 1][j - 1];
        for (int j = 0; j < n; ++j)
            f[i][j] = (f[i][j] - f[i - 1][j] * ((k - i) % mo) % mo + mo) % mo;
    }
    for (int i = 0; i < n; ++i)
        coe[i] = f[n - 1][i] * ivf[n - 1] % mo;
}

pair <ll, vector <ll> > p[M], q[M];
ll presum[N];
ll in_ex (ll ret = 0) {
    for (int s = 0; s < (1 << m); ++s) {
        ll sum = 0; int sgn = bitcnt[s] & 1 ? -1 : 1;
        for (int i = 0; i < m; ++i)
            if (s >> i & 1) sum += a[i];
        p[s].first = sum, p[s].second.resize(n, 0);
        for (int i = 0; i < n; ++i)
            p[s].second[i] = exp(sum % mo, i) * sgn % mo;
    }
    sort(p, p + (1 << m));
    for (int s = 0; s < (1 << (n - m)); ++s) {
        ll sum = 0; int sgn = bitcnt[s] & 1 ? -1 : 1;
        for (int i = 0; i < (n - m); ++i)
            if (s >> i & 1) sum += a[i + m];
        q[s].first = sum, q[s].second.resize(n, 0);
        for (int i = 0; i < n; ++i)
            q[s].second[i] = exp(sum % mo, i) * sgn % mo;
    }
    sort(q, q + (1 << (n - m)));
    memset(presum, 0, sizeof presum);
    for (int s = (1 << m) - 1, t = 0; ~s; --s) {
        for ( ; t < (1 << (n - m)) && k - n - (p[s].first + q[t].first) >= 0; ++t) {
            for (int i = 0; i < n; ++i) presum[i] = (presum[i] + q[t].second[i]) % mo;
        }
        for (int i = 0; i < n; ++i) {
            ll tmp = 0;
            for (int j = 0; j <= i; ++j)
                tmp = (tmp + cb[i][j] * p[s].second[j] % mo * presum[i - j] % mo) % mo;
            ret = (ret + coe[i] * tmp) % mo;
        }
    }
    return (ret % mo + mo) % mo;
}
signed main () {
    prework();
    for (int _ = read(); _; --_) {
        n = read(), m = (n + 1) / 2, k = 0;
        for (int i = 0; i < n; ++i)
            a[i] = read(), k += a[i] + 1;
        k /= 2;
        if (n == 1) {
            printf("1
");
            continue;
        }
        predo();
        printf("%lld
", in_ex());
    }
    return 0;
}
原文地址:https://www.cnblogs.com/psimonw/p/10727408.html