498C - Array and Operations 质因子分解+最大流

题目中说每一个good pair<u,v> 都满足(u+v)%2 == 1,即一个奇数,一个偶数。

首先我们要拿出一原点S,汇点T,S联到所有的num[odd]的质因子上,T联到所有的num[even]的质因子上,边的流量为num[i]中相应质因子的个数。

再根据给出的<u,v>,假设u为奇数,则从u的质因子上联到相等的v的质因子上,流量为INF。

丢到模板里跑一遍就好了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 6000007

using namespace std;

const int EDGE = 6000000,POINT = 4010;

struct E
{
    int u,v,Max,next;
} edge[EDGE];

int head[POINT];

int curr[POINT];

int Top;

void Link(int u,int v,int flow)
{
    //printf("u = %d v = %d flow = %d\n",u,v,flow);
    edge[Top].u = u;
    edge[Top].v = v;
    edge[Top].Max = flow;
    edge[Top].next = head[u];
    head[u] = Top++;
}

int dis[POINT],gap[POINT],pre[POINT];

queue<int> q;

void Updata_Dis(int S,int T,int n)
{
    memset(dis,-1,sizeof(dis));
    memset(gap,0,sizeof(gap));

    dis[T] = 0;
    gap[0] = 1;

    q.push(T);

    int f;

    while(q.empty() == false)
    {
        f = q.front();
        q.pop();

        for(int p = head[f]; p != -1; p = edge[p].next)
        {
            if(dis[edge[p].v] == -1)
            {
                dis[edge[p].v] = dis[f] + 1;
                gap[dis[f]+1]++;
                q.push(edge[p].v);
            }
        }
    }
}

int ISAP(int S,int T,int n)
{
    memcpy(curr,head,sizeof(curr));

    Updata_Dis(S,T,n);

    int flow = 0,u = pre[S] = S,p;

    while(dis[S] < n)
    {
        if(u == T)
        {
            int temp = INF,pos;
            for(p = S; p != T; p = edge[curr[p]].v)
            {
                if(temp > edge[curr[p]].Max)
                {
                    temp = edge[curr[p]].Max;
                    pos = p;
                }
            }

            for(p = S; p != T; p = edge[curr[p]].v)
            {
                edge[curr[p]].Max -= temp;
                edge[curr[p]^1].Max += temp;
            }

            flow += temp;
            u = pos;
        }

        for(p = curr[u]; p != -1; p = edge[p].next)
        {
            if(dis[edge[p].v]+1 == dis[u] && edge[p].Max)
                break;
        }

        if(p != -1)
        {
            curr[u] = p;
            pre[edge[p].v] = u;
            u = edge[p].v;
        }
        else
        {
            if((--gap[dis[u]]) == 0)
                break;

            int temp = n;

            for(p = head[u]; p != -1; p = edge[p].next)
            {
                if(temp > dis[edge[p].v] && edge[p].Max)
                {
                    curr[u] = p;
                    temp = dis[edge[p].v];
                }
            }

            dis[u] = temp+1;
            gap[dis[u]]++;
            u = pre[u];
        }
    }
    //printf("%d\n",flow);
    return flow;
}

bool vis[100010];
int pri[100010];

struct N
{
    int d,r;
};
vector<N> vec[110];

int main()
{
    int i,j,k,n,m;

    memset(vis,false,sizeof(vis));

    int ap;

    for(i = 2,ap = 0,n = 100000; i <= n; ++i)
    {
        if(vis[i])
            continue;
        pri[ap++] = i;
        for(j = i+i; j <= n; j += i)
            vis[j] = true;
    }

    scanf("%d %d",&n,&m);

    memset(head,-1,sizeof(head));
    Top = 0;

    int S = 1,T = 4001,ans,x,r = 2;

    for(i = 1; i <= n; ++i)
    {
        scanf("%d",&x);

        for(j = 0;j < ap && x >= pri[j]; ++j)
        {
            ans = 0;
            while(x%pri[j] == 0)
            {
                ans++;
                x /= pri[j];
            }

            if(ans)
            {
                vec[i].push_back((N){pri[j],r});
                if(i&1)
                {
                    Link(S,r,ans);
                    Link(r,S,0);
                }
                else
                {
                    Link(r,T,ans);
                    Link(T,r,0);
                }
                r++;
            }
        }

        if(x != 1)
        {
            vec[i].push_back((N){x,r});
            if(i&1)
            {
                Link(S,r,1);
                Link(r,S,0);
            }
            else
            {
                Link(r,T,1);
                Link(T,r,0);
            }
            r++;
        }
    }

    int u,v;

    for(i = 1;i <= m; ++i)
    {
        scanf("%d %d",&u,&v);

        if(v&1)
            swap(u,v);
        for(j = vec[u].size()-1,k = vec[v].size()-1;j >= 0 && k >= 0; )
        {
            if(vec[u][j].d == vec[v][k].d)
            {
                Link(vec[u][j].r,vec[v][k].r,INF);
                Link(vec[v][k].r,vec[u][j].r,0);
                --j,--k;
            }
            else if(vec[u][j].d > vec[v][k].d)
            {
                --j;
            }
            else
            {
                --k;
            }
        }
    }

    printf("%d\n",ISAP(S,T,T));

    return 0;
}
时间: 2024-10-29 10:45:48

498C - Array and Operations 质因子分解+最大流的相关文章

CodeForces 498C Array and Operations(最大流)

题目是给一些数和<数对>的下标,然后进行操作:对某个<数对>中的两个数同时除以一个都能被它们整除且不等于1的数,要求的就是最多能进行多少次操作. 除数一定是素数,就是要决定某素数要除哪些<数对>使除的次数最多, ik + jk is an odd number 可以想到这个是个二分图,数最多100个,然后就用最大流做了. 有了POJ2516的经验之后,马上想到,素数是独立的,进行若干次最大流而不是拆若干点跑最大流(10^9大概最多拆30个点吧).. 然后我还是没AC,因

codeforces 498C Array and Operations 网络流

传送门:cf 498C 给定一个长度为n的数组,已经m组下标对应关系(下标之和为奇数),现在可以对m组对应关系中的数同除一个大于1的整数,问最多能进行多少次这样的操作 要操作次数最大,每次处理的时候应该除质数. 下标之和为奇数,不难发现它构成了一张二分图. 枚举sqrt(10^9)的质数,找出n个数中各有多少个这样的质数k,然后建立对应的图,跑网络流最大流即可. /****************************************************** * File Name

Array and Operations

A. Array and Operations Time Limit: 1000ms Memory Limit: 262144KB 64-bit integer IO format: %I64d      Java class name: (Any) Submit Status You have written on a piece of paper an array of n positive integers a[1], a[2], ..., a[n] and m good pairs of

「CodeForces-498C」Array and Operations(数论+网络流)

「CodeForces-498C」Array and Operations给定n个点和m个边集,每次操作可以将相连边的两个点值同时除以一个公约数,问最大操作次数 题意 给定一个长为$n$的数组,以及$m$对下标为$(a,b)$的点对,且满足下标a+b为奇数(即奇数点只与偶数点匹配),每次操作可以将同一组的两个数同时除以一个公约数,问最多能进行多少次操作. 解法 显然题目所给的是一个二分图. 对于每个质因数分开考虑.对于奇数点,向源点连接一个容量为该因子个数的边:对于偶数点,则向汇点建立一个容量为

hdoj 1492 The number of divisors(约数) about Humble Numbers 【数论】【质因子分解 求和】

定理:一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的个数就是,(r1+1)*(r2+1)*...*(rk+1). 理解:为什么是加1之后再相乘,因为一个数的的因子数至少为1和他自身,但因为r1,r2..可以为0,所以因子的个数为(r1+1)... 拓展一下: 定理1: 一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的

BZOJ 1485: [HNOI2009]有趣的数列 [Catlan数 质因子分解]

1485: [HNOI2009]有趣的数列 Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…<a2n-1,所有的偶数项满足a2<a4<…<a2n: (3)任意相邻的两项a2i-1与a2i(1≤i≤n)满足奇数项小于偶数项,即:a2i-1<a2i. 现在的任务是:对于给定的n,请求出有多少个不同的长度为2n的有趣的数列.因为最后的答

HDU 2601 An easy problem(暴力枚举/质因子分解)

An easy problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7963    Accepted Submission(s): 1920 Problem Description When Teddy was a child , he was always thinking about some simple math p

luogu P2043 质因子分解

题目描述 对N!进行质因子分解. 输入输出格式 输入格式: 输入数据仅有一行包含一个正整数N,N<=10000. 输出格式: 输出数据包含若干行,每行两个正整数p,a,中间用一个空格隔开.表示N!包含a个质因子p,要求按p的值从小到大输出. 输入输出样例 输入样例#1: 10 输出样例#1: 2 8 3 4 5 2 7 1 说明 10!=3628800=(2^8)*(3^4)*(5^2)*7 质因数分解.. #include<cstdio> const int maxn=100006;

POJ1845:Sumdiv(求因子和+逆元+质因子分解)好题

题目链接:http://poj.org/problem?id=1845 定义: 满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元. 为什么要有乘法逆元呢? 当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元. 我们可以通过求b关于p的乘法逆元k,将a乘上k再模p, 即(a*k) mod p.其结果与(a/b) mod p等价. 题目解析:让求a^b的因子和modk,因为是大数没法直接求,因为求因子和函数是乘性函数,所以首先要质因子分解,化成n