据说连连看是世界上最难的问题……
据说UESTC某同学在玩消消乐是凝视屏幕,语出惊人:我在深搜……
但是这题其实很简单
把所有可能的组合都建边,容量1,费用,注意,题目要求最大,那么我们就把它建成负的,求最小(熟悉的操作)
然后注意拆点,拆之前的点连源点,拆之后的连汇点,上述建边是在拆点的两个部分之间
完了
上代码:
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 8003;
const int MAXE = 500003;
int ans;
struct Edge {
int from, to, nxt, cap, flow, cost;
Edge() {}
Edge(int _from, int _to, int _nxt, int _cap, int _flow, int _cost):from(_from), to(_to), nxt(_nxt), cap(_cap), flow(_flow), cost(_cost) {}
}e[MAXE];
int h[MAXN], p;
int source, sink;
int cur[MAXN];
int d[MAXN];
queue<int> q;
bool exist[MAXN];
inline int read()
{
int ch;int x=0;int f=1;ch=getchar();
while (ch!='-'&&(ch<'0'||ch>'9'))
ch=getchar();
ch=='-'?f=-1:x=ch-'0',ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
inline void add_edge(int x, int y, int cap, int cost) {
e[p] = Edge(x, y, h[x], cap, 0, cost); h[x] = p++;
e[p] = Edge(y, x, h[y], 0, 0, -cost); h[y] = p++;
}
bool SPFA() {
memset(d, 0x3f, sizeof(d));
memset(exist, 0, sizeof(exist));
memset(cur, -1, sizeof(cur));
q.push(source);
d[source] = 0;
exist[source] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
exist[u] = 0;
for(int i = h[u]; ~i; i = e[i].nxt) {
int v = e[i].to;
if(e[i].cap > e[i].flow && d[v] > d[u] + e[i].cost) {
d[v] = d[u] + e[i].cost;
cur[v] = i;
if(!exist[v]) {
q.push(v);
exist[v] = 1;
}
}
}
}
return d[sink] != INF;
}
int MCMF() {
int cost = 0;
while(SPFA()) {
int flow = INF;
for(int i = sink; i != source; i = e[cur[i]].from) flow = min(flow, e[cur[i]].cap - e[cur[i]].flow);
for(int i = sink; i != source; i = e[cur[i]].from) {
e[cur[i]].flow += flow;
e[cur[i] ^ 1].flow -= flow;
}
cost += flow * d[sink];
ans += flow;
}
return cost;
}
inline int gcd(int x,int y)
{
int i,j;
if(x==0)
return y;
if(y==0)
return x;
for(i=0;0==(x&1);++i) x>>=1;
for(j=0;0==(y&1);++j) y>>=1;
if(j<i)
i=j;
while(1)
{
if(x<y)
x^=y,y^=x,x^=y;
if(0==(x-=y))
return y<<i;
while(0==(x&1))
x>>=1;
}
}
bool check(int i, int j) {
int tmp = (int)sqrt(i * i - j * j);
if(tmp * tmp != i * i - j * j) return 0;
if(gcd(j, tmp) != 1) return 0;
return 1;
}
int l, r;
int f;
signed main()
{
l = read(), r = read();
source = 0; sink = r * 3; memset(h, -1, sizeof(h));
for(int i = l + 1; i <= r; i++) {
for(int j = l; j < i; j++) {
if(check(i, j)) {
add_edge(i, j + r, 1, - i - j);
add_edge(j, i + r, 1, - i - j);
}
}
}
for(int i = l; i <= r; i++) add_edge(source, i, 1, 0);
for(int i = l; i <= r; i++) add_edge(i + r, sink, 1, 0);
f = MCMF();
printf("%d %d\n", ans/2, - f/2);
return 0;
}