题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2661
题意:给出一个区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x^2-y^2是一个完全平方数z^2,并且y与z互质,那么就可以将x和y一起消除,同时得到x+y点分数。要求就是,消除的数对尽可能多的前提下,得到的分数尽量多。
思路:首先暴力出所有合法的数对(x,y)。然后将每个用到的数字拆成两个点,每个数对连一条边。最后的答案除以2即可。
struct node { int u,v,next,cost,cap; }; node edges[N*100]; int head[N],e; void add(int u,int v,int cap,int cost) { edges[e].u=u; edges[e].v=v; edges[e].cap=cap; edges[e].cost=cost; edges[e].next=head[u]; head[u]=e++; } void Add(int u,int v,int cap,int cost) { add(u,v,cap,cost); add(v,u,0,-cost); } int pre[N],F[N],C[N],visit[N]; int SPFA(int s,int t,int n) { int i; for(i=0;i<=n;i++) F[i]=0,C[i]=INF*10000,visit[i]=0; queue<int> Q; Q.push(s); F[s]=INF; C[s]=0; int u,v,cost,cap; while(!Q.empty()) { u=Q.front(); Q.pop(); visit[u]=0; for(i=head[u];i!=-1;i=edges[i].next) { if(edges[i].cap>0) { v=edges[i].v; cost=edges[i].cost; cap=edges[i].cap; if(C[v]>C[u]+cost) { C[v]=C[u]+cost; F[v]=min(F[u],cap); pre[v]=i; if(!visit[v]) visit[v]=1,Q.push(v); } } } } return F[t]; } void MCMF(int s,int t,int n) { int i,x,temp,M=0; int ans=0; while(temp=SPFA(s,t,n)) { M+=temp; for(i=t;i!=s;i=edges[pre[i]].u) { x=pre[i]; ans+=edges[x].cost*temp; edges[x].cap-=temp; edges[x^1].cap+=temp; } } PR(M>>1,(M*INF-ans)>>1); } int n,m,s,t,cnt; int Gcd(int x,int y) { if(y==0) return x; return Gcd(y,x%y); } int c[N*N],b[N],L[400],R[400]; int main() { RD(n,m); if(n>m) swap(n,m); int i,j,k; for(i=1;i<=1000;i++) c[i*i]=i; for(i=n;i<=m;i++) for(j=i+1;j<=m;j++) { k=j*j-i*i; if(c[k]&&Gcd(i,c[k])==1) { b[i]=b[j]=1; cnt++; L[cnt]=i; R[cnt]=j; } } int x=0; for(i=n;i<=m;i++) if(b[i]) b[i]=++x; s=0; t=x+x+1; clr(head,-1); for(i=n;i<=m;i++) if(b[i]) Add(s,b[i],1,0),Add(b[i]+x,t,1,0); FOR1(i,cnt) { Add(b[L[i]],x+b[R[i]],1,INF-L[i]-R[i]); Add(b[R[i]],x+b[L[i]],1,INF-L[i]-R[i]); } MCMF(s,t,t+1); }