【bzoj3158】 千钧一发

http://www.lydsy.com/JudgeOnline/problem.php?id=3158 (题目链接)

题意

  给出n个装置,每个装置i有一个特征值a[i]和一个能量值b[i],要求选出能量值和尽可能大的装置,使它们两两之间至少满足一下两条件中的1个条件:1.不存在T,a[i]*a[i]+a[j]*a[j]=T*T;2.gcd(a[i],a[j])>1。

Solution

  通过观察与思考,我们可以发现,如果把不符合条件的两个装置用边连接起来,最后要求的就是带权最大独立集,然而这是一般图,难道还要去写最大团?这是不现实的,考虑它是否满足二分图的性质。

  写写画画以后,发现:

    对于两个偶数来说,它们之间的gcd至少为2,也就是满足第二个条件,任意两个偶数之间都没有边相连。

    对于两个奇数来说,它们的平方和=4*(a[i]+1)*(a[j]+1),一定满足条件1,任意两个奇数之间都没有边相连。

  于是这就是个二分图了,奇数放左边,偶数放右边,然后最小割求二分图带权最大独立集。

细节

  sqrt出来放到一个LL里面。。。如果放在一个double中,那么就不是正整数T了。。。难怪一直0ms Wa。。

代码

// bzoj3158
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=1010;
struct edge {int to,next,w;}e[maxn*maxn*2];
int head[maxn],d[maxn];
LL a[maxn],b[maxn];
int cnt=1,n,m,es,et,ans;

int gcd(int a,int b) {return b==0 ? a : gcd(b,a%b);}
void link(int u,int v,int w) {
	e[++cnt]=(edge){v,head[u],w};head[u]=cnt;
	e[++cnt]=(edge){u,head[v],0};head[v]=cnt;
}
bool bfs() {
	memset(d,-1,sizeof(d));
	queue<int> q;q.push(es);d[es]=0;
	while (!q.empty()) {
		int x=q.front();q.pop();
		for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]<0) {
				d[e[i].to]=d[x]+1;
				q.push(e[i].to);
			}
	}
	return d[et]>0;
}
int dfs(int x,int f) {
	if (x==et || f==0) return f;
	int used=0,w;
	for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]==d[x]+1) {
			w=dfs(e[i].to,min(e[i].w,f-used));
			e[i].w-=w;e[i^1].w+=w;
			used+=w;if (used==f) return used;
		}
	if (!used) d[x]=-1;
	return used;
}
void Dinic() {while (bfs()) ans-=dfs(es,inf);}
int main() {
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
	for (int i=1;i<=n;i++) scanf("%lld",&b[i]),ans+=b[i];
	es=n+1;et=n+2;
	for (int i=1;i<=n;i++) {
		if (a[i]%2==1) link(es,i,b[i]);
		else link(i,et,b[i]);
	}
	for (int i=1;i<=n;i++) {
		if (a[i]%2==0) continue;
		for (int j=1;j<=n;j++) if (a[j]%2==0) {
				if (gcd(a[i],a[j])!=1) continue;
				LL x=sqrt(a[i]*a[i]+a[j]*a[j]);
				if (x*x!=a[i]*a[i]+a[j]*a[j]) continue;
				link(i,j,inf);
			}
	}
	Dinic();
	printf("%d",ans);
    return 0;
}

  

时间: 2024-10-09 23:52:05

【bzoj3158】 千钧一发的相关文章

bzoj3158: 千钧一发(最小割)

3158: 千钧一发 题目:传送门 题解: 这是一道很好的题啊...极力推荐 细看题目:要求一个最大价值,那么我们可以转换成求损失的价值最小 那很明显就是最小割的经典题目啊?! 但是这里两个子集的分化并不明显...GG 耐心一点,从题目的要求再入手: 对于第二个要求,如果两点的a值都为偶数,那么肯定满足 那如果两个数都为奇数的话,也必定满足要求一,证明如下: 1.一个奇数的平方%4为1,一个偶数的平方%4为0 2.两个奇数的平方和%4为2 3.如果两个奇数的平方和是一个奇数的平方,那么%4应该为

【个人整理】网络流

说明:S,表示超级原点,T表示超级汇点,<i,j,k(,l)>表示i到j建边,流量为k(,费用为l) bzoj4177 Mike的农场 题解:考虑割,养牛的收益为a[i],养羊b[i],对于每个位置<S,i,ai> <i,T,bi>分别表示养牛和养羊,对于两个互相影响的位置<i,j,ci>:做最小割可以满足前两个限制 :第三个限制,如果全养牛可以获得d,新建一个点x,考虑要求全养牛的位置为集合为s,<S,x,d> , <x,si,inf&g

【bzoj3158】千钧一发 最小割

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

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

3275: Number Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 748  Solved: 316[Submit][Status][Discuss] Description 有N个正整数,需要从中选出一些数,使这些数的和最大.若两个数a,b同时满足以下条件,则a,b不能同时被选1:存在正整数C,使a*a+b*b=c*c2:gcd(a,b)=1 Input 第一行一个正整数n,表示数的个数. 第二行n个正整数a1,a2,?an. Output

bzoj 3158 千钧一发(最小割)

3158: 千钧一发 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 767  Solved: 290[Submit][Status][Discuss] Description Input 第一行一个正整数N. 第二行共包括N个正整数,第 个正整数表示Ai. 第三行共包括N个正整数,第 个正整数表示Bi. Output 共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值. Sample Input 4 3 4 5 12 9

bzoj 3158: 千钧一发

1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define M 200009 7 #define inf 2139062143 8 using namespace std; 9 int cnt=1,n,m,S,T,d[M],q[2*M],f[M],head[M],next[10*M],u[

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】【3158】千钧一发

网络流/最小割 这题跟BZOJ 3275限制条件是一样的= =所以可以用相同的方法去做……只要把边的容量从a[i]改成b[i]就行了- (果然不加当前弧优化要略快一点) 1 /************************************************************** 2 Problem: 3158 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:196 ms 7 Memory:13028 kb 8

漫谈可视化Prefuse(五)

伴随着前期的基础积累,翻过API,读过一些Demo,总觉得自己已经摸透了Prefuse,小打小闹似乎已经无法满足内心膨胀的自己.还记得儿时看的<武状元苏乞儿>中降龙十八掌最后一张居然是空白页,在千钧一发之际以为自己要嗝屁了,一阵东风让苏乞儿明白了,最后一章要做的原来是--整合.没错,今天我们就来好好谈谈整合! 看懂API不代表你会灵活运用某个类,会用一些类不代表能实现小功能,耍的了小功能不一定会做可视化工具整合,整合之道,奥妙无穷! 前篇回顾:上篇<漫谈可视化Prefuse(四)---被