凡是考智商的题里面总会有这么一种消除游戏。不过现在面对的这关连连看可不是QQ游戏里那种考眼力的游戏。我们的规则是,给出一个闭区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x2-y2是一个完全平方数z2,并且y与z互质,那么就可以将x和y连起来并且将它们一起消除,同时得到x+y点分数。那么过关的要求就是,消除的数对尽可能多的前提下,得到足够的分数。快动手动笔算一算吧。
凡是考智商的题里面总会有这么一种消除游戏。不过现在面对的这关连连看可不是QQ游戏里那种考眼力的游戏。我们的规则是,给出一个闭区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x2-y2是一个完全平方数z2,并且y与z互质,那么就可以将x和y连起来并且将它们一起消除,同时得到x+y点分数。那么过关的要求就是,消除的数对尽可能多的前提下,得到足够的分数。快动手动笔算一算吧。
只有一行,两个整数,分别表示a,b。
两个数,可以消去的对数,及在此基础上能得到的最大分数。
对于30%的数据,1<=a,b<=100
对于100%的数据,1<=a,b<=1000
费用流的应用
这道题想了很久应该如何限定每个数只能选一次,后来看了题解才发现不是这样子。
对于每一个数i,我们拆成两个点i1和i2。对于每一个符合条件的数对(i,j),加边(i1,j2,1,i+j)(j1,i2,1,i+j),然后从源点向所有i1连边(s,i1,1,0),从所有i2向汇点连边(i2,t,1,0)。跑最大费用最大流。(只要把所有边的费用取反即可,这里负环一定不存在,所以就不用考虑了)
你可能会问:这样每个点不就可能被选两次了吗?但实际上(i1,j2)(j1,i2)这两条边一定同时被选或同时不选。为什么呢?通俗一点理解,因为两条边容量、费用完全一样。
所以最终答案只要除以2就可以了。
那消去的对数如何解决呢?统计一下所有指向汇点t的边中被选的个数,即流量为1的个数。记得最后输出时答案要除以2。
#include
#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair
#define maxn 2010
#define maxm 2000000
#define inf 1000000000
using namespace std;
struct edge_type
{
int from,to,next,v,c;
}e[maxm];
int head[maxn],dis[maxn],p[maxn];
int a,b,s,t,cnt=1,ans=0,tot=0;
bool inq[maxn];
inline void add_edge(int x,int y,int v,int c)
{
e[++cnt]=(edge_type){x,y,head[x],v,c};head[x]=cnt;
e[++cnt]=(edge_type){y,x,head[y],0,-c};head[y]=cnt;
}
inline int spfa()
{
queueq;
memset(inq,false,sizeof(inq));
F(i,1,t) dis[i]=inf;
dis[s]=0;q.push(s);inq[s]=true;
while (!q.empty())
{
int x=q.front();q.pop();inq[x]=false;
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if (e[i].v&&dis[y]>dis[x]+e[i].c)
{
dis[y]=dis[x]+e[i].c;
p[y]=i;
if (!inq[y]){q.push(y);inq[y]=true;}
}
}
}
return dis[t]!=inf;
}
inline void mcf()
{
ans=0;
while (spfa())
{
int tmp=inf;
for(int i=p[t];i;i=p[e[i].from]) tmp=min(tmp,e[i].v);
ans+=tmp*dis[t];
for(int i=p[t];i;i=p[e[i].from]){e[i].v-=tmp;e[i^1].v+=tmp;}
}
}
inline bool check(int x,int y)
{
int tmp=x*x-y*y,z=(int)sqrt(tmp);
if (z*z!=tmp) return false;
if (y