CF468E Permanent

https://www.luogu.com.cn/problem/CF468E

不会做,差点把心态搞没

考虑积和式的组合意义
可以看做是一个二分图的所有的完美匹配的边权乘积的和
考虑把每条边\(w\)拆成\(1\)\(w-1\),那么对于\(w-1\)的的边构成的二分图,只需要找它的任意一个匹配,然后直接乘上未匹配的点的阶乘即可(剩下的点随意匹配)。状压\(DP\)即可,考虑优化,注意到如果某一列后面都不会再用到了,可以不状压这一列,分析可得最坏可以被卡到
\(O(m^22^{\frac{m}{2}})\)
因为换一种行的枚举顺序貌似就卡不掉了,所以没有特意去卡

官方题解是根号分治的做法,但实际跑起来并不比上述做法跑得快。

code:

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define mod 1000000007
#define N 2000050
using namespace std;
struct {
    int u, v, c;
} a[N];
int n, m, bu[N], bv[N], n1, n2;
ll fac[N], ok[N];
map<ll, ll> f[105][105];
vector<pair<int, int> > e[N];
int main() {
    scanf("%d%d", &n, &m);
    fac[0] = 1;
    for(int i = 1; i <= n; i ++) fac[i] = fac[i - 1] * i % mod;

    for(int i = 1; i <= m; i ++) {
        scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].c); a[i].c = (a[i].c - 1 + mod) % mod;
        bu[++ n1] = a[i].u, bv[++ n2] = a[i].v;
    }
    sort(bu + 1, bu + 1 + n1), n1 = unique(bu + 1, bu + 1 + n1) - bu - 1;
    sort(bv + 1, bv + 1 + n2), n2 = unique(bv + 1, bv + 1 + n2) - bv - 1;
    
    for(int i = 1; i <= m; i ++) {
        a[i].u = lower_bound(bu + 1, bu + 1 + n1, a[i].u) - bu;
        a[i].v = lower_bound(bv + 1, bv + 1 + n2, a[i].v) - bv;
        e[a[i].u].push_back(make_pair(a[i].v, a[i].c));
    }

    for(int i = n1; i >= 1; i --) {
        ok[i] = ok[i + 1];
        for(auto x : e[i]) ok[i] |= (1ll << x.fi);
    }

    f[0][0][0] = 1;
    for(int i = 0; i < n1; i ++)   
        for(int j = 0; j <= i; j ++) 
            for(auto x : f[i][j]) {
                (f[i + 1][j][x.fi & ok[i + 1]] += x.se) %= mod;
                if(x.se)
                for(auto y : e[i + 1]) if(!((x.fi >> y.fi) & 1) && y.se) {
                    (f[i + 1][j + 1][(x.fi | (1ll << y.fi)) & ok[i + 1]] += 1ll * y.se * x.se % mod) %= mod;
                }
            }

    ll ans = 0;
    for(int i = 0; i <= n1; i ++) 
        for(auto x : f[n1][i]) 
            ans = (ans + 1ll * x.se * fac[n - i] % mod) % mod;//, printf("%lld  %lld    %lld\n", x.fi, x.se, fac[n - i]);
    printf("%lld", ans);
    return 0;
}
posted @ 2022-02-16 15:35  lahlah  阅读(80)  评论(0编辑  收藏  举报