Gym - 101853B New Assignment

Gym - 101853B New Assignment

传送门:Gym - 101853B

  • Gym - 101853B New Assignment
    • 题意
    • 题解
      • 代码
        • 大佬的算法orz直接暴力orz
        • o(n)素数筛(欧拉函数)
        • 唯一素数分解
        • ac代码

题意

给你一堆人,分男女,每个人有个值,单独一个人可以一组,一男一女也可以凑成一组,但是要求每一对男女的值的gcd不能等于1。 同时题目保证给出的数中任意三个人的gcd都等于1。求最少分成多少组。人数小于等于1e4,一共100组数据

题解

求最少分成多少组,就是求最大匹配嘛,这个很容易想到。(ps:题意读错了另说,例如我的某位可爱的沙雕队友)n有1e4,那就isap搞一发。但是怎么建图呢。
gcd不等于1,首先想到的就是朴素算法,n^2复杂度,虽然cf评测机好,但是1e8*1e2怎么也肯定t了。
然后想到剪枝,搞两个队列,每次枚举点,一旦gcd不得1,就把两个数除以gcd,如果除完得1了,就不再进把他进队了。这么搞了一发,又t。毕竟最坏结果还是1e8。
然后就想到先搞一发,然后再唯一素数分解。
然后咋办呢,把每个素数都搞一个vector,把所有数唯一素数分解出来的素数,把这个数的编号噎到每个他有的素数的vector里,然后枚举每个vector,暴力匹配一下。这样复杂度是o(edge)的。而且他说了,任意三个gcd都得1,这样每个vector的size不超过2,复杂度就及其科学了。同时注意一下,加边的时候,把x和y重新标号一下,连接的时候,边方向别错了,我重标号之后就是小的是连超源,大的连超汇,这样就是min连max就好了。
ps:这破题代码真长。

然后在我刚写完这篇博客之后,大佬告诉我一个更快的。。。更好的写法orz,这个算法叫做直接暴力。。。

代码

大佬的算法orz直接暴力orz

#include
#define F first
#define S second
#define endl "\n"
#define rep(i , a , b) for (int i=a; i<(b); i++)
#define re0(i , a)     for (int i=0; i<(a); i++)
using namespace std;

typedef pair<int, int> ii;
typedef long long ll;
typedef long double ld;

const int mod = 7 + 1e9;
const int N = 5 + 1e4;
pair<char, int>a[N];
bool b[N];
int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        memset(b, 0, sizeof b);
        int n, i, j = 0, ans = 0;
        cin >> n;
        re0(i, n)
        cin >> a[i].S;
        re0(i, n)
        cin >> a[i].F;
        sort(a, a + n);
        while (a[j].F == 'F') j++;
        int l;
        for (i = 0; i < j; ++i) {
            for (l = j; l < n; ++l) {
                if (!b[l])
                    if (__gcd(a[l].S, a[i].S) != 1) {
                        ans++;
                        b[l] = 1;
                        b[i] = 1;
                        break;
                    }
            }
        }
        re0(i, n) {
            if (!b[i])ans++;
        }
        cout << ans << endl;
    }
}

先贴一发素数筛和唯一素数分解的模板

o(n)素数筛(欧拉函数)

int phi[maxn], prime[maxn], tot, fa[maxn];
bool notp[maxn];

void getphi(int M) {
    phi[1] = 1;
    for (int i = 2; i <= M; i++) {
        if (!notp[i]) {
            prime[++tot] = i;
            fa[i] = tot;
            phi[i] = i - 1;//i是素数
        }
        for (int j = 1; j <= tot && i * prime[j] <= M; j++) {
            notp[i * prime[j]] = 1;//不是素数
            if (i % prime[j] == 0) {// 如果i mod p==0,那么φ( i*p )=p*φ( i )
                phi[i * prime[j]] = phi[i] * prime[j];
                break;//筛素数省时
            }
                // 若i mod p≠0,那么φ(i*p)=φ(i)*(p-1)
            else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
        }
    }
    return;
}

唯一素数分解

void prime_explode(ll x, vector &save) {
     ll w = x;
    save.clear();
    for (int i = 1; i <= tot && (ll) prime[i] * prime[i] <= w; i++) {
        if (x % prime[i] == 0) {
            pii now(prime[i], 0);
            while (x % prime[i] == 0) {
                x /= prime[i];
                now.second++;
            }
            save.push_back(now);
        }
    }
    if (x != 1) {
        save.push_back(pii(x, 1));
    }
}

ac代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 

#pragma comment(linker, "/STACK:102400000,102400000")
#define fir first
#define sec second
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define clr(x) memset(x,0,sizeof(x))
#define cld(x) memset(x,-1,sizeof(x))
#define clx(x) memset(x,63,sizeof(x))
#define cln(x) memset(x,-64,sizeof(x))
#define rush() int T;rd.read(T);while(T--)
#define pi 3.1415926
#define VM 100047
#define EM 400047
//#define rd(x) scanf("%d",&x);

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair pll;

const int inf = 0x3f3f3f3f;
const ll llf = 0x3f3f3f3f3f3f3f3f;
const int maxn = (int) 1e6 + 7;
const double eps = 1e-10;
const ll mod1 = (int) 1e9 + 7;
const ll mod2 = 998244353;
const ll has = 99959;
const int dx[] = {0, 1, 0, -1};
const int dy[] = {1, 0, -1, 0};

struct ISAP {
    struct E {
        int to, frm, nxt, cap;
    } edge[EM];

    int head[VM], e, n, m, src, des;
    int dep[VM], gap[VM];
    int que[VM];

    void init(int _n, int _s, int _r) {
        n = _n;
        src = _s;
        des = _r;
        e = 0;
        cld(head);
        //clr(edge);
    }

    void AddEdge(int cu, int cv, int cw) {
        edge[e].frm = cu;
        edge[e].to = cv;
        edge[e].cap = cw;
        edge[e].nxt = head[cu];
        head[cu] = e++;
        edge[e].frm = cv;
        edge[e].to = cu;
        edge[e].cap = 0;
        edge[e].nxt = head[cv];
        head[cv] = e++;
    }


    void BFS() {
        memset(dep, -1, sizeof(dep));
        memset(gap, 0, sizeof(gap));
        gap[0] = 1;
        int front = 0, rear = 0;
        dep[des] = 0;
        que[rear++] = des;
        int u, v;
        while (front != rear) {
            u = que[front++];
            front = front % VM;
            for (int i = head[u]; i != -1; i = edge[i].nxt) {
                v = edge[i].to;
                if (edge[i].cap != 0 || dep[v] != -1)
                    continue;
                que[rear++] = v;
                rear = rear % VM;
                ++gap[dep[v] = dep[u] + 1];
            }
        }
    }

    int cur[VM], stack[VM];

    int Max_flow() {

        int res = 0;
        BFS();
        int top = 0;
        memcpy(cur, head, sizeof(head));
        int u = src, i;
        while (dep[src] < n) {
            if (u == des) {
                int temp = inf, inser = n;
                for (i = 0; i != top; ++i)
                    if (temp > edge[stack[i]].cap) {
                        temp = edge[stack[i]].cap;
                        inser = i;
                    }
                for (i = 0; i != top; ++i) {
                    edge[stack[i]].cap -= temp;
                    edge[stack[i] ^ 1].cap += temp;
                }
                res += temp;
                top = inser;
                u = edge[stack[top]].frm;
            }

            if (u != des && gap[dep[u] - 1] == 0)
                break;
            for (i = cur[u]; i != -1; i = edge[i].nxt)
                if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1)
                    break;

            if (i != -1) {
                cur[u] = i;
                stack[top++] = i;
                u = edge[i].to;
            } else {
                int min = n;
                for (i = head[u]; i != -1; i = edge[i].nxt) {
                    if (edge[i].cap == 0)
                        continue;
                    if (min > dep[edge[i].to]) {
                        min = dep[edge[i].to];
                        cur[u] = i;
                    }
                }
                --gap[dep[u]];
                ++gap[dep[u] = min + 1];
                if (u != src)
                    u = edge[stack[--top]].frm;
            }
        }
        return res;
    }
} sap;

template<class T>
class in_out {
public:

    inline bool read(T &ret) {
        char c;
        int sgn;
        if (c = static_cast<char>(getchar()), c == EOF) {
            return false;
        }
        while (c != '-' && (c < '0' || c > '9')) {
            c = static_cast<char>(getchar());
        }
        sgn = (c == '-') ? -1 : 1;
        ret = (c == '-') ? 0 : (c - '0');
        while (c = static_cast<char>(getchar()), c >= '0' && c <= '9') {
            ret = ret * 10 + (int) (c - '0');
        }
        ret *= sgn;
        return true;
    }

    void out(T a) {
        if (a < 0) {
            putchar('-');
            a = -a;
        }
        if (a >= 10)
            out(a / 10);
        putchar(a % 10 + '0');
    }
};

in_out<int> rd;

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

struct rec {
    int x, id;
    char ch[2];

    rec(int _x = 0, int _id = 0) {
        x = _x;
        id = _id;
    }
} a[maxn];

int b[maxn], c[maxn];

int n;
int phi[maxn], prime[maxn], tot, fa[maxn];
bool notp[maxn];

void getphi(int M) {
    phi[1] = 1;
    for (int i = 2; i <= M; i++) {
        if (!notp[i]) {
            prime[++tot] = i;
            fa[i] = tot;
            phi[i] = i - 1;//i是素数
        }
        for (int j = 1; j <= tot && i * prime[j] <= M; j++) {
            notp[i * prime[j]] = 1;//不是素数
            if (i % prime[j] == 0) {// 如果i mod p==0,那么φ( i*p )=p*φ( i )
                phi[i * prime[j]] = phi[i] * prime[j];
                break;//筛素数省时
            }
                // 若i mod p≠0,那么φ(i*p)=φ(i)*(p-1)
            else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
        }
    }
    return;
}

void prime_explode(ll x, vector &save) {
    ll w = x;
    save.clear();
    for (int i = 1; i <= tot && (ll) prime[i] * prime[i] <= w; i++) {
        if (x % prime[i] == 0) {
            pii now(prime[i], 0);
            while (x % prime[i] == 0) {
                x /= prime[i];
                now.second++;
            }
            save.push_back(now);
        }
    }
    if (x != 1) {
        save.push_back(pii(x, 1));
    }
}

vector<int> vec[maxn];
vector v;

int main() {
    std::ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    getphi(maxn);
    rush() {
        clr(vec);
        rd.read(n);
        int mx = 0;
        for (int i = 1; i <= n; i++) {
            rd.read(a[i].x);
            mx = max(mx, a[i].x);
        }
        int num1 = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%s", a[i].ch);
            if (a[i].ch[0] == 'M')
                num1++;

        }
        int s = n + 10;
        int t = s + 1;
        sap.init(t + 10, s, t);
        int numb = 0;
        int numc = num1;
        for (int i = 1; i <= n; i++) {
            v.clear();
            if (a[i].ch[0] == 'M') {
                numb++;
                prime_explode(a[i].x, v);
                for (auto &x  : v) {
                    vec[fa[x.first]].push_back(numb);
                }
                sap.AddEdge(s, numb, 1);
            } else {
                numc++;
                prime_explode(a[i].x, v);
                for (auto &x  : v) {
                    vec[fa[x.first]].push_back(numc);
                }
                sap.AddEdge(numc, t, 1);
            }
        }

        for (int i = 1; i <= mx; i++) {
            if (!vec[i].empty()) {
                for (int j = 0; j < vec[i].size() - 1; j++) {
                    for (int k = j + 1; k < vec[i].size(); k++) {
                        sap.AddEdge(min(vec[i][j], vec[i][k]), max(vec[i][j], vec[i][k]), 1);
                    }
                }
            }
        }

        printf("%d\n", n - sap.Max_flow());
    }

    return 0;
}

你可能感兴趣的:(图论,gym,数学)