bzoj4205 卡牌配对

  卡牌配对

题目背景:

bzoj4205

分析:我相信很多人第一反应都是暴力连边然后暴力二分图匹配,然后我的常数还没有小到n230000,所以我们来想想该怎么办,考虑到200以内的质数只有46个,我们可以选择增加3 * 46 * 46个点,将左边的某种属性有第i个质因数,另一个属性有第j个质因数的点连向对应的一个点,并将这个点与右边满足上述条件的点相连,然后新建源点汇点就可以跑最大流了,大概是一个70000个点,2000000条边的网络流(200以内的数最多3个质因数,所以最多不超过27条边),他竟然让大胆玩高渐进复杂度,那当然就直接上吧。

Source

/*
    created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
  
inline char read() {
    static const int IN_LEN = 1024 * 1024;
    static char buf[IN_LEN], *s, *t;
    if (s == t) {
        t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
        if (s == t) return -1;
    }
    return *s++;
}
  
///*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = read(), iosig = false; !isdigit(c); c = read()) {
        if (c == -1) return ;
        if (c == '-') iosig = true; 
    }
    for (x = 0; isdigit(c); c = read()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/
  
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
    if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
    *oh++ = c;
}
  
template<class T>
inline void W(T x) {
    static int buf[30], cnt;
    if (x == 0) write_char('0');
    else {
        if (x < 0) write_char('-'), x = -x;
        for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
        while (cnt) write_char(buf[cnt--]);
    }
}
  
inline void flush() {
    fwrite(obuf, 1, oh - obuf, stdout);
}
  
/*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
        if (c == '-') iosig = true; 
    for (x = 0; isdigit(c); c = getchar()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/
 
const int MAXN = 70000 + 10;
const int MAXX = 200 + 5;
const int prime[50] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 
                       47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 
                       107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 
                       167, 173, 179, 181, 191, 193, 197, 199};
 
struct node {
    int to, w, rev;
    node(int to = 0, int w = 0, int rev = 0) : to(to), w(w), rev(rev) {}
} ;
 
struct data {
    int a, b, c;
} x[MAXN], y[MAXN];
 
std::vector<node> edge[MAXN];
 
int n1, n2, n, s, t;
int id[3][MAXX][MAXX], dis[MAXN], gap[MAXN];
 
inline void add_edge(int x, int y, int w) {
    edge[x].push_back(node(y, w, edge[y].size()));
    edge[y].push_back(node(x, 0, edge[x].size() - 1));
}
 
inline void read_in() {
    R(n1), R(n2);
    for (int i = 1; i <= n1; ++i) R(x[i].a), R(x[i].b), R(x[i].c);
    for (int i = 1; i <= n2; ++i) R(y[i].a), R(y[i].b), R(y[i].c);
}
 
inline int solve(int n, int *a) {
    int top = 0;
    for (int i = 2; i <= sqrt(n); ++i) {
        if (n % i == 0) a[++top] = i;
        while (n % i == 0) n /= i;      
    }
    if (n != 1) a[++top] = n;
    return top;
}
 
inline void build_graph() {
    n = n1 + n2;
    for (int i = 0; i < 3; ++i)
        for (int j = 1; j <= 46; ++j)
            for (int k = 1; k <= 46; ++k)
                id[i][prime[j]][prime[k]] = ++n;
     
    s = ++n, t = ++n;
    int a[MAXX], b[MAXX], c[MAXX];
    for (int i = 1; i <= n1; ++i) {
        add_edge(s, i, 1);
        int top1 = solve(x[i].a, a);
        int top2 = solve(x[i].b, b);
        int top3 = solve(x[i].c, c);
        for (int k1 = 1; k1 <= top1; ++k1)
            for (int k2 = 1; k2 <= top2; ++k2)
                add_edge(i, id[0][a[k1]][b[k2]], 1);
        for (int k1 = 1; k1 <= top1; ++k1)
            for (int k3 = 1; k3 <= top3; ++k3)
                add_edge(i, id[1][a[k1]][c[k3]], 1);
        for (int k2 = 1; k2 <= top2; ++k2)
            for (int k3 = 1; k3 <= top3; ++k3)
                add_edge(i, id[2][b[k2]][c[k3]], 1);
    }
    for (int i = 1; i <= n2; ++i) {
        add_edge(i + n1, t, 1);
        int top1 = solve(y[i].a, a);
        int top2 = solve(y[i].b, b);
        int top3 = solve(y[i].c, c);
        for (int k1 = 1; k1 <= top1; ++k1)
            for (int k2 = 1; k2 <= top2; ++k2)
                add_edge(id[0][a[k1]][b[k2]], n1 + i, 1);
        for (int k1 = 1; k1 <= top1; ++k1)
            for (int k3 = 1; k3 <= top3; ++k3)
                add_edge(id[1][a[k1]][c[k3]], n1 + i, 1);
        for (int k2 = 1; k2 <= top2; ++k2)
            for (int k3 = 1; k3 <= top3; ++k3)
                add_edge(id[2][b[k2]][c[k3]], n1 + i, 1);
    }
}
 
///*
inline int sap(int cur, int flow, int s, int t, int n) {
    if (cur == t) return flow;
    int del = 0;
    static int temp[MAXN];
    for (int p = temp[cur]; p < edge[cur].size(); ++p) {
        node *e = &edge[cur][p];
        if (e->w > 0 && dis[e->to] + 1 == dis[cur]) {
            int ret = sap(e->to, std::min(flow - del, e->w), s, t, n);
            e->w -= ret, edge[e->to][e->rev].w += ret, temp[cur] = p;
            if ((del += ret) == flow || dis[cur] >= n) 
                return temp[cur] = 0, del;
        }
    }
    if (--gap[dis[cur]] == 0) dis[s] = n;
    return gap[++dis[cur]]++, temp[cur] = 0, del;
}
 
inline int sap(int s, int t, int n) {
    int ret = 0;
    for (gap[0] = n; dis[s] < n; ) ret += sap(s, ~0u >> 1, s, t, n);
    return ret;
}
//*/

int main() {
    read_in();
    build_graph();
    std::cout << sap(s, t, n);
    return 0;
}


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值