「BZOJ2661」[BJ WC2012] 连连看
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
题解
拆点费用流。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define ll long long #define inf 0x7fffffff #define T 2001 using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int a,b,cnt=1; int ans1,ans2; int head[2005],q[2005],dis[2005],from[2005]; bool inq[2005]; struct data{int to,from,next,v,c;}e[2000005]; void ins(int u,int v,int w,int c) { e[++cnt].to=v;e[cnt].from=u; e[cnt].next=head[u];head[u]=cnt; e[cnt].v=w;e[cnt].c=c; } void insert(int u,int v,int w,int c) {ins(u,v,w,c);ins(v,u,0,-c);} inline int gcd(int a,int b){return b==0?a:gcd(b,a%b);} bool spfa() { for(int i=0;i<=T;i++)dis[i]=-inf; int t=0,w=1; dis[0]=0;q[0]=0;inq[0]=1; while(t!=w) { int now=q[t];t++;if(t==2001)t=0; for(int i=head[now];i;i=e[i].next) if(e[i].v&&e[i].c+dis[now]>dis[e[i].to]) { dis[e[i].to]=e[i].c+dis[now]; from[e[i].to]=i; if(!inq[e[i].to]) { inq[e[i].to]=1; q[w++]=e[i].to; if(w==2001)w=0; } } inq[now]=0; } if(dis[T]==-inf)return 0; return 1; } void dfs() { int x=inf; for(int i=from[T];i;i=from[e[i].from]) x=min(e[i].v,x); for(int i=from[T];i;i=from[e[i].from]) {ans2+=x*e[i].c;e[i].v-=x;e[i^1].v+=x;} } bool jud(int x,int y) { if(x<y)swap(x,y); int t=int(sqrt(x*x-y*y)); return (gcd(y,t)==1&&x*x-y*y==t*t); } int main() { a=read();b=read(); for(int i=a;i<=b;i++) for(int j=a;j<=b;j++) if(jud(i,j)&&i!=j)insert(i,j+1000,1,i+j); for(int i=a;i<=b;i++) insert(0,i,1,0),insert(i+1000,T,1,0); while(spfa())dfs(); for(int i=2;i<=cnt;i+=2) if(e[i].to==T&&!e[i].v)ans1++; printf("%d %d",ans1/2,ans2/2); return 0; } |
这道题其实是一个二分图,但是需要打表验证一下,黄学长直接就说了=-=
黄学长,同样的处理,跑的zkw就会WA,但是跑mcmf就能A,请问是怎么个情况QAQ…
写错了。。。
黄学长,为什么是gcd(x,y)==1而不是gcd(y,z)==1,题目说的是y与z互质啊。。。
已更正
黄学长,为什么只建从大的数到小的数的边,然后输出an1,ans2就wa掉了
黄学长,你的代码好像WA掉了
已更正