BZOJ 2661: [BeiJing wc2012]连连看( 费用流 )

拆点, 能够消的连边, 然后跑费用流就OK了.

----------------------------------------------------------------------------------------

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
 
using namespace std;
 
const int maxn = 2009;
const int INF = 1 << 30;
 
int X[maxn], Y[maxn], V, S, T;
 
int Gcd(int x, int y) {
return y ? Gcd(y, x % y) : x;
}
 
struct edge {
int to, cap, cost;
edge *next, *rev;
} E[1000000], *pt = E, *head[maxn], *p[maxn];
 
inline void Add(int u, int v, int c, int w) {
pt->to = v;
pt->cap = c;
pt->cost = w;
pt->next = head[u];
head[u] = pt++;
}
 
inline void AddEdge(int u, int v, int c, int w) {
Add(u, v, c, w);
Add(v, u, 0, -w);
head[u]->rev = head[v];
head[v]->rev = head[u];
}
 
queue<int> q;
bool inq[maxn];
int d[maxn], a[maxn];
 
int Work() {
int Cost = 0, Flow = 0;
for(; ; ) {
for(int i = 0; i < V; i++)
inq[i] = false, d[i] = INF;
d[S] = 0;
a[S] = INF;
q.push(S);
while(!q.empty()) {
int x = q.front(); q.pop();
inq[x] = false;
for(edge* e = head[x]; e; e = e->next) if(e->cap && d[e->to] > d[x] + e->cost) {
d[e->to] = d[x] + e->cost;
p[e->to] = e;
a[e->to] = min(a[x], e->cap);
if(!inq[e->to])
q.push(e->to), inq[e->to] = true;
}
}
if(d[T] == INF)
break;
Flow += a[T];
Cost += d[T] * a[T];
for(int x = T; x != S; x = p[x]->rev->to) {
p[x]->cap -= a[T];
p[x]->rev->cap += a[T];
}
}
printf("%d %d\n", Flow >> 1, -Cost >> 1);
}
 
void Init() {
S = 0; T = 1; V = 2;
int l, r;
scanf("%d%d", &l, &r);
for(int i = l; i <= r; i++)
X[i] = V++, Y[i] = V++;
for(int i = l; i <= r; i++)
for(int j = l; j < i; j++) {
int v = i * i - j * j, t = (int) sqrt(v);
if(t * t == v && Gcd(j, t) == 1) {
AddEdge(X[j], Y[i], 1, -i - j);
AddEdge(X[i], Y[j], 1, -i - j);
}
}
for(int i = l; i <= r; i++) {
AddEdge(S, X[i], 1, 0);
AddEdge(Y[i], T, 1, 0);
}
}
 
int main() {
Init();
Work();
return 0;
}

---------------------------------------------------------------------------------------- 

2661: [BeiJing wc2012]连连看

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 844  Solved: 317
[Submit][Status][Discuss]

Description

 凡是考智商的题里面总会有这么一种消除游戏。不过现在面对的这关连连看可不是QQ游戏里那种考眼力的游戏。我们的规则是,给出一个闭区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x2-y2是一个完全平方数z2,并且y与z互质,那么就可以将x和y连起来并且将它们一起消除,同时得到x+y点分数。那么过关的要求就是,消除的数对尽可能多的前提下,得到足够的分数。快动手动笔算一算吧。

Input

        
 只有一行,两个整数,分别表示a,b。

Output

 两个数,可以消去的对数,及在此基础上能得到的最大分数。

Sample Input

1 15

Sample Output

2 34

HINT

对于30%的数据,1<=a,b<=100

对于100%的数据,1<=a,b<=1000

Source

 

posted @ 2016-01-08 18:53  JSZX11556  阅读(184)  评论(0编辑  收藏  举报