时间限制:1秒 内存限制:64M
【问题描述】
凡是考智商的题里面总会有这么一种消除游戏。不过现在面对的这关连连看可不是QQ游戏里那种考眼力的游戏。我们的规则是,给出一个闭区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x^2-y^2是一个完全平方数(即x^2-y^2=z^2),并且y与z互质,那么就可以将x和y连起来并且将它们一起消除,同时得到x+y点分数。那么过关的要求就是,消除的数对尽可能多的前提下,得到足够的分数。快动手动笔算一算吧。
【输入格式】
只有一行,两个整数,分别表示a,b。
【输出格式】
两个数,可以消去的对数,及在此基础上能得到的最大分数。
【输入样例】
1 15
【输出样例】
2 34
【数据范围】
对于30%的数据,1<=a,b<=100
对于100%的数据,1<=a,b<=1000
【来源】
BzOJ2661
一道简单的网络流,每个点分成2个一个入点一个出点,如果2个数满足条件就分别从1个的入点直接连边到一个的出点就可以了(当然源点连每个入点,每个出点连汇点),边权是2个数的和,其他边权值全部是0,最后求个最大费用最大流就出来了。
详细代码如下:
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=2005;
const int inf=200000005;
struct edge
{
int u,v,f,c,w,next;
}e[maxn*maxn];
vector<int>g[maxn];
int f[maxn],cnt=-1,q[maxn*maxn],d[maxn],fa[maxn],vis[maxn];
int a,b,s,t;
void add(int u,int v,int c,int w)
{
e[++cnt]=(edge){u,v,c,0,w,f[u]};f[u]=cnt;
e[++cnt]=(edge){v,u,0,0,-w,f[v]};f[v]=cnt;
}
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
bool work(int x,int y)
{
int k=sqrt(y*y-x*x);
if(y*y-x*x!=k*k) return 0;
return gcd(k,x)==1;
}
int spfa()
{
memset(vis,0,sizeof(vis));
for(int i=s;i<=t;i++) d[i]=-inf;
int frond=0,root=0;
fa[s]=-1;
q[root++]=s;
d[s]=0;
while(frond!=root)
{
int i=q[frond++];
vis[i]=0;
for(int k=f[i];k!=-1;k=e[k].next)
{
int j=e[k].v,c=e[k].w;
if(d[j]>=d[i]+c||e[k].f==e[k].c) continue;
d[j]=d[i]+c;
fa[j]=k;
if(vis[j]) continue;
vis[j]=1;
q[root++]=j;
}
}
return d[t];
}
void dinic()
{
int flow=0,cost=0;
while(1)
{
int c=spfa();
if(c==-inf) break;
cost+=c;
flow++;
int id=fa[t];
while(id!=-1)
{
e[id].c++;
e[id^1].c--;
id=fa[e[id].u];
}
}
printf("%d %d",flow/2,cost/2);
}
void dfs(int i,int id)
{
if(vis[i]) printf("wrong!\n");
vis[i]=id;
int tt=g[i].size();
for(int k=0;k<tt;k++)
{
int j=g[i][k];
if(j==fa[i]) continue;
fa[j]=i;
dfs(j,3-id);
}
}
int main()
{
//freopen("linking.in","r",stdin);
//freopen("linking.out","w",stdout);
scanf("%d%d",&a,&b);
s=0,t=2*b+1;
int ans=0;
for(int i=s;i<=t;i++) f[i]=-1;
for(int i=a;i<=b;i++)
for(int j=i+1;j<=b;j++)
if(work(i,j))
{
add(i,j+b,1,i+j);
add(j,i+b,1,i+j);
}
for(int i=a;i<=b;i++)
{
add(s,i,1,0);
add(i+b,t,1,0);;
}
dinic();
return 0;
}