EOJ月赛:唐纳德和他的数学老师(二分图匹配 & 最大流)

来源:互联网 发布:频率发生器软件 编辑:程序博客网 时间:2024/06/05 06:36

Time limit per test: 1.0 seconds

Memory limit: 256 megabytes

唐纳德是一个数学天才。有一天,他的数学老师决定为难一下他。他跟唐纳德说:「现在我们来玩一个游戏。这个游戏总共 n 轮,每一轮我都会给你一个数(第 i 轮给出的数是 ai)。你每次要回答一个数,是我给出的这个数的质因数,并且你说出的数不能重复。」

因为数学老师是刻意为难,所以这个游戏很有可能不可能进行到最后。但是聪明的数学老师早就已经知道这个游戏最多能进行几轮了。现在他把问题抛给了你,想看看你知不知道。

注意,1 不是质数。

Input

输入具有如下形式:

na1 a2  an

第一行一个整数 n (1n3 000)。

第二行 n 个整数用空格隔开,a1,a2,,an (2ai106)。

Output

输出游戏最多能进行几轮。

Examples

input
37 6 3
output
3
input
52 2 2 2 2
output
1

Source

EOJ Monthly 2017.12

思路:天气冷脑子都不好使了。先将每个数分解质因数,要每个人选一个数不重复,显然就是最大匹配问题或者最大流问题。

①最大匹配每处理一个数,就将它和它的质因子建边,然后跑一次匈牙利看是否增多了一条边即可。

②二分答案+最大流,对每个质因子拆点(不拆也可以^_^),建容量为1的边,源点--第某轮--某轮的质因子--某论的质因子副本--汇点。

# include <iostream># include <cstdio># include <cstring># include <vector># include <algorithm># define mp make_pair# define pb push_backusing namespace std;typedef long long LL;const int maxn = 1e6+30;int a[3003], l[maxn];vector<int>v[3003], g[3003];bool vis[maxn];bool dfs(int u){    for(int i=0; i<g[u].size(); ++i)    {        int j = g[u][i];        if(!vis[j])        {            vis[j] = true;            if(l[j] == -1 || dfs(l[j]))            {                l[j] = u;                return true;            }        }    }    return false;}int main(){    int n, ans;    scanf("%d",&n);    memset(l, -1, sizeof(l));    for(int i=1; i<=n; ++i)    {        scanf("%d",&a[i]);        if(a[i] == 1)        {            n = i-1;            break;        }        for(int j=2; j*j<=a[i]; ++j)        {            while(a[i]%j==0)            {                v[i].pb(j);                a[i]/=j;            }        }        if(a[i]!=1) v[i].pb(a[i]);    }    if(n==0) return 0*puts("0");    for(int i=1; i<=n; ++i)    {        for(int j=0; j<v[i].size(); ++j)            g[i].pb(v[i][j]);        memset(vis, false, sizeof(vis));        if(!dfs(i)) break;        else ans=i;    }    printf("%d\n",ans);    return 0;}

# include <iostream># include <cstdio># include <cstring># include <vector># include <algorithm># define mp make_pair# define pb push_backusing namespace std;typedef long long LL;const int maxn = 1e6+3003;int a[3003];vector<int>v[3003];struct node{    int v, w, next;}edge[maxn<<2];int n, cnt, Next[maxn*2], len=1e6;int dis[maxn*2], source, sink, q[maxn<<2];int vis[maxn*2];void add(int u, int v, int w){    edge[cnt] = {v,w,Next[u]};    Next[u] = cnt++;    edge[cnt] = {u,0,Next[v]};    Next[v] = cnt++;}bool bfs(){    memset(dis, -1, sizeof(dis));    dis[source] = 0;    int l=0, r=0;    q[r++] = source;    while(l<r)    {        int u = q[l];        ++l;        for(int i=Next[u]; i!=-1; i=edge[i].next)        {            int v = edge[i].v, w=edge[i].w;            if(w>0 && dis[v]==-1)            {                dis[v] = dis[u]+1;                q[r++] = v;            }        }    }    return dis[sink] != -1;}int dfs(int u, int pre){    if(u == sink) return pre;    int ans = 0, f = 0;    for(int i=Next[u]; i!=-1; i=edge[i].next)    {        int v = edge[i].v, w=edge[i].w;        if(dis[v] == dis[u]+1 && w>0 && (f=dfs(v, min(w, pre))))        {            edge[i].w -= f;            edge[i^1].w += f;            pre -= f;            ans += f;            if(!pre) break;        }    }    if(ans) return ans;    dis[u] = -1;    return 0;}bool check(int x){    cnt = 0;    source=0, sink=2e6+n;    memset(vis, 0, sizeof(vis));    memset(Next, -1, sizeof(Next));    for(int i=1; i<=x; ++i)    {        add(0, i, 1);        for(int j=0; j<v[i].size(); ++j)        {            int k=v[i][j];            if(++vis[k]==1)            {                add(k+n, k+n+len, 1);                add(k+n+len, sink, 1);            }            add(i, k+n, 1);        }    }    int max_flow=0;    while(bfs()) max_flow += dfs(source, 0x3f3f3f3f);    return max_flow == x;}int main(){    scanf("%d",&n);    for(int i=1; i<=n; ++i)    {        scanf("%d",&a[i]);        if(a[i] == 1)        {            n = i-1;            break;        }        for(int j=2; j*j<=a[i]; ++j)        {            while(a[i]%j==0)            {                v[i].pb(j);                a[i]/=j;            }        }        if(a[i]!=1) v[i].pb(a[i]);    }    if(n==0) return 0*puts("0");    int l=1,r=n;    while(l<=r)    {        int mid = l+r>>1;        if(check(mid)) l=mid+1;        else r=mid-1;    }    printf("%d\n",r);    return 0;}