【BZOJ-3275&3158】Number&千钧一发 最小割

3275: Number

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 748  Solved: 316
[Submit][Status][Discuss]

Description

有N个正整数,需要从中选出一些数,使这些数的和最大。
若两个数a,b同时满足以下条件,则a,b不能同时被选
1:存在正整数C,使a*a+b*b=c*c
2:gcd(a,b)=1

Input

第一行一个正整数n,表示数的个数。

第二行n个正整数a1,a2,?an。

Output

最大的和。

Sample Input

5
3 4 5 6 7

Sample Output

22

HINT

n<=3000。

Source

网络流

3158: 千钧一发

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 984  Solved: 359
[Submit][Status][Discuss]

Description

Input

第一行一个正整数N。

第二行共包括N个正整数,第 个正整数表示Ai。

第三行共包括N个正整数,第 个正整数表示Bi。

Output

共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。

Sample Input

4
3 4 5 12
9 8 30 9

Sample Output

39

HINT

1<=N<=1000,1<=Ai,Bi<=10^6

Source

Katharon+#1

Solution

一开始没仔细读题,看成同时满足两个,WA了几波后才发现看错了...

对奇数偶数讨论一下,奇数之间肯定满足1.偶数之间肯定满足2

最小割就好

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
int Gcd(int a,int b)
{
    if (b==0) return a; else return Gcd(b,a%b);
}
bool check(long long a,long long b)
{
    if (Gcd(a,b)>1) return true;
    long long T=sqrt(a*a+b*b); if (T*T!=a*a+b*b) return true;
    return false;
}
#define maxn 5000
#define maxm 1000010
int N,A[maxn],B[maxn],tot;
struct Edgenode{int next,to,cap;}edge[maxm];
int head[maxn],cnt=1;
void add(int u,int v,int w)
{
    cnt++;
    edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;
}
void insert(int u,int v,int w) {add(u,v,w); add(v,u,0);}
int cur[maxn],dis[maxn],S,T;
bool bfs()
{
    queue<int> q;
    memset(dis,-1,sizeof(dis));
    q.push(S); dis[S]=0;
    while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i; i=edge[i].next)
                if (edge[i].cap && dis[edge[i].to]==-1)
                    dis[edge[i].to]=dis[now]+1,q.push(edge[i].to);
        }
    return dis[T]!=-1;
}
int dfs(int loc,int low)
{
    if (loc==T) return low;
    int w,used=0;
    for (int i=cur[loc]; i; i=edge[i].next)
        if (edge[i].cap && dis[edge[i].to]==dis[loc]+1)
            {
                w=dfs(edge[i].to,min(low-used,edge[i].cap));
                edge[i].cap-=w; edge[i^1].cap+=w; used+=w;
                if (edge[i].cap) cur[loc]=i; if (used==low) return low;
            }
    if (!used) dis[loc]=-1;
    return used;
}
#define inf 0x7fffffff
int dinic()
{
    int tmp=0;
    while (bfs())
        {
            for (int i=S; i<=T; i++) cur[i]=head[i];
            tmp+=dfs(S,inf);
        }
    return tmp;
}
void Build()
{
    S=0,T=N+1;
    for (int i=1; i<=N; i++)
        if ((A[i]%2)) insert(S,i,A[i]); else insert(i,T,A[i]);
    for (int i=1; i<=N; i++)
        for (int j=1; j<=N; j++)
            if ((A[i]%2) && !(A[j]%2) && !check(A[i],A[j]))
                insert(i,j,inf);
}
int main()
{
    N=read();
    for (int i=1; i<=N; i++) A[i]=read(),tot+=A[i];
    //for (int i=1; i<=N; i++) B[i]=read(),tot+=B[i];
    Build();
    int maxflow=dinic();
    printf("%d\n",tot-maxflow);
    return 0;
}

BZOJ-3275

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
int Gcd(int a,int b)
{
    if (b==0) return a; else return Gcd(b,a%b);
}
bool check(long long a,long long b)
{
    if (Gcd(a,b)>1) return true;
    long long T=sqrt(a*a+b*b); if (T*T!=a*a+b*b) return true;
    return false;
}
#define maxn 3000
#define maxm 1000010
int N,A[maxn],B[maxn],tot;
struct Edgenode{int next,to,cap;}edge[maxm];
int head[maxn],cnt=1;
void add(int u,int v,int w)
{
    cnt++;
    edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;
}
void insert(int u,int v,int w) {add(u,v,w); add(v,u,0);}
int cur[maxn],dis[maxn],S,T;
bool bfs()
{
    queue<int> q;
    memset(dis,-1,sizeof(dis));
    q.push(S); dis[S]=0;
    while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now]; i; i=edge[i].next)
                if (edge[i].cap && dis[edge[i].to]==-1)
                    dis[edge[i].to]=dis[now]+1,q.push(edge[i].to);
        }
    return dis[T]!=-1;
}
int dfs(int loc,int low)
{
    if (loc==T) return low;
    int w,used=0;
    for (int i=cur[loc]; i; i=edge[i].next)
        if (edge[i].cap && dis[edge[i].to]==dis[loc]+1)
            {
                w=dfs(edge[i].to,min(low-used,edge[i].cap));
                edge[i].cap-=w; edge[i^1].cap+=w; used+=w;
                if (edge[i].cap) cur[loc]=i; if (used==low) return low;
            }
    if (!used) dis[loc]=-1;
    return used;
}
#define inf 0x7fffffff
int dinic()
{
    int tmp=0;
    while (bfs())
        {
            for (int i=S; i<=T; i++) cur[i]=head[i];
            tmp+=dfs(S,inf);
        }
    return tmp;
}
void Build()
{
    S=0,T=N+1;
    for (int i=1; i<=N; i++)
        if ((A[i]%2)) insert(S,i,B[i]); else insert(i,T,B[i]);
    for (int i=1; i<=N; i++)
        for (int j=1; j<=N; j++)
            if ((A[i]%2) && !(A[j]%2) && !check(A[i],A[j]))
                insert(i,j,inf);
}
int main()
{
    N=read();
    for (int i=1; i<=N; i++) A[i]=read();
    for (int i=1; i<=N; i++) B[i]=read(),tot+=B[i];
    Build();
    int maxflow=dinic();
    printf("%d\n",tot-maxflow);
    return 0;
}

BZOJ-3158

时间: 2024-09-29 18:43:58

【BZOJ-3275&3158】Number&千钧一发 最小割的相关文章

BZOJ 2007 海拔(平面图最小割-最短路)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2007 题意:给出一个n*n的格子,那么顶点显然有(n+1)*(n+1)个.每两个相邻顶点之间有两条边,这两条边是有向的,边上有权值..左上角为源点,右下角为汇点,求s到t的最小割. 思路:很明显这是一个平面图,将其转化为最 短路.我们将s到t之间连一条边,左下角为新图的源点S,右上角区域为新图的终点T,并且为每个格子编号.由于边是有向的,我们就要分析下这条边应该是哪 个点向哪个点的边.

BZOJ 3275 Number &amp;&amp; 3158 千钧一发 最小割

题目大意:给出一些数字,要求选出一些数字并保证所有数字和最大,要求这其中的数字任意两个至少满足一个条件,则不能同时被选:1.这两个数的平方和是完全平方数.2.gcd(a,b) = 1. 思路:我们可以将奇数和偶数分开来讨论,奇数不满足1,偶数不满足2,所以奇数和奇数,偶数和偶数不会互相影响.之后O(n^2)的讨论其他数字对,有影响就连边,流量正无穷,最后跑最小割最最大获利. CODE: #define _CRT_SECURE_NO_WARNINGS #include <cmath> #incl

[BZOJ 3144] [Hnoi2013] 切糕 【最小割】

题目链接:BZOJ - 3144 题目分析 题意:在 P * Q 的方格上填数字,可以填 [1, R] . 在 (x, y) 上填 z 会有 V[x][y][z] 的代价.限制:相邻两个格子填的数字的差的绝对值不能超过 D . 求一个合法的最小总代价. 这道题是一个最小割模型,直接说建图吧. 建图:每个点 (x, y) 拆成 R 个点,(x, y, z) 代表 (x, y) 填 z. 然后从 S 向 (*, *, 1) 连 INF ,从 (*, *, R) 向 T 连 INF . 然后对于 (i

[BZOJ 3894] 文理分科 【最小割】

题目链接:BZOJ - 3894 题目分析 最小割模型,设定一个点与 S 相连表示选文,与 T 相连表示选理. 那么首先要加上所有可能获得的权值,然后减去最小割,即不能获得的权值. 那么对于每个点,从 S 向它连权值为它选文的价值的边,从它向 T 连权值为它选理的价值的边. 对于一个点,它和与它相邻的点构成了一个集合,这个集合如果都选文,可以获得一个价值v1,如果都选理,可以获得一个价值 v2. 只要这个集合中有一个点选文,就无法获得 v2,只要有一个点选理,就无法获得 v1. 那么处理方式就是

BZOJ 3774: 最优选择( 最小割 )

最小割...二分染色然后把颜色不同的点的源汇反过来..然后就可以做了. 某个点(x,y): S->Id(x,y)(回报), Id(x,y)->T(代价), Id(i,j)&&Id(相邻节点)->newId(i,j)(+oo), newId(i,j)->T(回报) 然后染色不同的点反过来就可以了. 初始时答案为2*∑回报, 这样每个点要么割掉1个回报,要么割掉2个回报, 要么割掉1回报+代价.都对应着每一种方案 ----------------------------

BZOJ 3144 HNOI 2013 切糕 最小割

题目大意:给出一个三维的点阵,没个点都有可能被切割,代价就是这个点的权值.相邻的切割点的高度差不能超过D,问最小的花费使得上下分开. 思路:很裸的最小割模型,很神的建图. S->第一层的点,f:INF 所有点->它下面的点,f:INF 一个点的入->一个点的出,f:val[i] (i,j,k) - > (i - d,j,k),f:INF 最下面一层的点->T:f:INF 然后跑最小割就是答案. 为什么见:http://www.cnblogs.com/zyfzyf/p/4182

【bzoj3158】千钧一发 最小割

题目描述 输入 第一行一个正整数N. 第二行共包括N个正整数,第 个正整数表示Ai. 第三行共包括N个正整数,第 个正整数表示Bi. 输出 共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值. 样例输入 4 3 4 5 12 9 8 30 9 样例输出 39 题解 最小割 两个奇数一定满足条件1,两个偶数一定满足条件2,所以不满足条件的一定只存在于奇数和偶数之间. 因此S向奇数连边,偶数向T连边,不满足条件的奇数和偶数之间连边. 然后求最小割,答案为sum-mincut

BZOJ 1934 善意的投票(最小割)

把人分成两个集合,一个赞成睡觉,一个反对睡觉.好朋友连一条容量为1的双向边,s向赞成睡觉的连边,反对睡觉的向t连边. 那么这个图的一个割就对应着一个方案.如果割掉s和v的边,就代表v投意见与它自己相反的票,t和v的边同理.割掉u和v的边,就代表了这对好朋友之间意见不同. 这样求出一个割之后,好朋友之间意见不同的边都被割去了. 求出此图的最小割即为答案. # include <cstdio> # include <cstring> # include <cstdlib>

BZOJ 2007 NOI2010 海拔 平面图最小割

题目大意:YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路(简称道路),每条双向道路连接主干道上两个相邻的交叉路口.下图为一张YT市的地图(n = 2),城市被划分为2×2个区域,包括3×3个交叉路口和12条双向道路. 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期间YT市每条道路两个方向的人流量,即在高峰期间沿着