列表

详情


NC17427. Decoding graphs

描述

Niuniu likes cryptology. His friend, Gougou, sent him a graph as his birthday present. The graph is encoded, so Niuniu must answer a question to decode it. The graph has n vertices and m edges. Every vertex has a non-negative integer ai. Here follows the question:
You need to assign each vertex another non-negative integer bi, satisfying:
1. For an edge (u, v),bu ≠ bv.
2. For a vertex u,0 ≤ bu ≤ au.
3. b1 xor b2 xor ... xor bn = C. (xor means exclusive OR)
What is the number of valid assignments modulo 998244353?
Can you help Niuniu answer the question?

输入描述

The first line contains three integers n, m, C,which are the number of vertices, number of edges and the given number C.
The second line contains n non-negative integers, a1, a2, a3, ..., an, separated by a space.
The following m lines each line contains two different numbers, u and v, meaning that there is an edge between u and v. There are no multiple edges in the graph.
1 ≤ n ≤ 13, 0 ≤ m ≤ n(n-1)/2, 0 ≤ ai, C ≤ 1018

输出描述

Print a single line with one number, which means the answer.

示例1

输入:

3 1 2
1 2 3
1 2

输出:

4

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 980ms, 内存消耗: 10096K, 提交时间: 2018-08-24 16:39:10

#include<bits/stdc++.h>

const int N = 14;
const int M = 1000010;
const int moder = 998244353;
typedef long long ll;

int inv[M];

void init(){
    inv[1] = 1;
    for (int i = 2; i < M; ++ i){
        inv[i] = (moder - 1ll * (moder / i) * inv[moder % i] % moder) % moder;
    }
}

int powermod(int a, int exp){
    int ret = 1;
    for ( ; exp > 0; exp >>= 1){
        if (exp & 1){
            ret = 1ll * ret * a % moder;
        }
        a = 1ll * a * a % moder;
    }
    return ret;
}

struct poly{
    int a[N];

    poly(){memset(a, 0, sizeof(a));}

    int &operator [](const int &n){
        return a[n];
    }

    poly operator +(const poly &p)const{
        poly ret;
        for (int i = 0; i < N; ++ i){
            ret.a[i] = a[i] + p.a[i];
            ret.a[i] -= ret.a[i] >= moder ? moder : 0;
        }
        return ret;
    }

    poly operator -(const poly &p)const{
        poly ret;
        for (int i = 0; i < N; ++ i){
            ret.a[i] = a[i] - p.a[i];
            ret.a[i] += ret.a[i] < 0 ? moder : 0;
        }
        return ret;
    }

    poly operator *(const poly &p)const{
        poly ret;
        for (int i = 0; i < N; ++ i){
            for (int j = 0; i + j < N; ++ j){
                ret.a[i + j] = (ret.a[i + j] + 1ll * a[i] * p.a[j]) % moder;
            }
        }
        return ret;
    }

    poly operator *(const int &p)const{
        poly ret;
        for (int i = 0; i < N; ++ i){
            ret.a[i] = 1ll * a[i] * p % moder;
        }
        return ret;
    }
};

void FMT(poly *f, int len, int type){
    for (int j = 0; j < len; ++ j){
        for (int i = 0; i < 1 << len; ++ i){
            if (i >> j & 1){
                if (type == 0){
                    f[i] = f[i] + f[i ^ 1 << j];
                }
                else{
                    f[i] = f[i] - f[i ^ 1 << j];
                }
            }
        }
    }
}

ll a[N];
bool mat[N][N];
poly p[1 << N], q[1 << N];
int ways[1 << N];
ll min[1 << N];
std::vector <int> vec[1 << N];
int coef[1 << N];

int solve(std::vector <ll> vec, ll c){
    std::sort(vec.begin(), vec.end());
    if (vec.back() == 0){
        return c == 0;
    }
    int maxv = 63 - __builtin_clzll(vec.back());
    int maxc = c ? 63 - __builtin_clzll(c) : -1;
    if (maxv < maxc){
        return 0;
    }
    int dp[2] = {1, 0};
    for (int i = 0, sz = vec.size(); i < sz - 1; ++ i){
        int small = std::min(vec[i] + 1, 1ll << maxv) % moder;
        int big = std::max(0ll, vec[i] - (1ll << maxv) + 1) % moder;
        int tmp0 = (1ll * dp[0] * small + 1ll * dp[1] * big) % moder;
        int tmp1 = (1ll * dp[1] * small + 1ll * dp[0] * big) % moder;
        dp[0] = tmp0, dp[1] = tmp1;
    }
    int ret = dp[maxv == maxc];
    *(vec.rbegin()) ^= 1ll << maxv;
    c ^= 1ll << maxv;
    ret += solve(vec, c);
    ret -= ret >= moder ? moder : 0;
    return ret;
}

int ans = 0;

void dfs(int set, int coe, int chosen){
    if (!set){
        ans = (ans + 1ll * coe * ways[chosen]) % moder;
        return;
    }
    for (auto u : vec[set]){
        int ncoe = 1ll * coe * coef[u] % moder;
        int nchosen = chosen;
        if (__builtin_parity(u)){
            nchosen ^= 1 << min[u];
        }
        else{
            ncoe = 1ll * ncoe * (a[min[u]] % moder + 1) % moder;
        }
        dfs(set ^ u, ncoe, nchosen);
    }
}

int main(){
    init();
    int n, m;
    ll c;
    scanf("%d%d%lld", &n, &m, &c);
    for (int i = 0; i < n; ++ i){
        scanf("%lld", &a[i]);
    }
    for (int i = 0, u, v; i < m; ++ i){
        scanf("%d%d", &u, &v);
        -- u, -- v;
        mat[u][v] = mat[v][u] = true;
    }
    memset(min, -1, sizeof(min));
    for (int i = 0; i < 1 << n; ++ i){
        std::vector <int> vec;
        std::vector <ll> vec1;
        for (int j = 0; j < n; ++ j){
            if (i >> j & 1){
                vec.push_back(j);
                vec1.push_back(a[j]);
                if (min[i] == -1 || a[min[i]] > a[j]){
                    min[i] = j;
                }
            }
        }
        bool flag = true;
        for (int j = 0, sz = vec.size(); j < sz; ++ j){
            for (int k = j + 1; k < sz; ++ k){
                if (mat[vec[j]][vec[k]]){
                    flag = false;
                }
            }
        }
        p[i][vec.size()] = flag;
        if (i){
            ways[i] = solve(vec1, c);
        }
    }
    FMT(p, n, 0);
    for (int i = 0; i < 1 << n; ++ i){
        p[i][0] = 0;
        poly now = p[i], tmp = p[i];
        for (int j = 1; j <= n; ++ j){
            q[i] = q[i] + now * (j & 1 ? inv[j] : (moder - inv[j]));
            now = now * tmp;
        }
    }
    FMT(q, n, 1);
    for (int i = 0; i < 1 << n; ++ i){
        coef[i] = q[i][__builtin_popcount(i)];
    }
    for (int i = 1; i < 1 << n; ++ i){
        for (int j = 1; j <= i; ++ j){
            if ((i & j) != j) continue;
            for (int k = 0; k < n; ++ k){
                if ((i >> k & 1) || (j >> k & 1)){
                    if ((i & j) >> k & 1){
                        vec[i].push_back(j);
                    }
                    break;
                }
            }
        }
    }
    dfs((1 << n) - 1, 1, 0);
    printf("%d\n", ans);
    return 0;
}

上一题