P4134 [BJOI2012]连连看

题目描述

凡是考智商的题里面总会有这么一种消除游戏。不过现在面对的这关连连看可不是QQ游戏里那种考眼力的游戏。我们的规则是,给出一个闭区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x^2-y^2是一个完全平方数z^2,并且y与z互质,那么就可以将x和y连起来并且将它们一起消除,同时得到x+y点分数。那么过关的要求就是,消除的数对尽可能多的前提下,得到足够的分数。快动手动笔算一算吧。

输入格式

只有一行,两个整数,分别表示a,b。

输出格式

两个数,可以消去的对数,及在此基础上能得到的最大分数。

输入输出样例

输入 #1
1 15
输出 #1
2 34

说明/提示

对于30%的数据,1<=a,b<=100

对于100%的数据,1<=a,b<=1000

思路

从题目中可看出这题为拆点并跑最大流最大费用。对于每个符合题目条件的(i,j),我们拆为i,i+b,j,j+b。并将i与j+b,i+b与j相连,建边,这样虽然可以省去自己与自己建边,但需要将结果除去2。

代码

#include<bits/stdc++.h>
#define N 10700
#define M 107000
#define inf 1<<29
using namespace std;
struct node{
    int y,z,p,next;
}e[M*2];
int tot=1,head[N],maxflow=0,ans=0,s,t;
void add(int x,int y,int z,int p){
    e[++tot].y=y;e[tot].z=z;e[tot].p=p;
    e[tot].next=head[x];head[x]=tot;
}
int incf[N],v[N],pre[N],d[N];
bool spfa(){
    queue<int> q;
    memset(d,0xcf,sizeof(d));
    memset(v,0,sizeof(v));
    q.push(s);d[s]=0;v[s]=1;
    incf[s]=inf;
    while(q.size()){
        int x=q.front();v[x]=0;q.pop();
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y,z=e[i].z;
            if(!z) continue;
            if(d[y]<d[x]+e[i].p){
                d[y]=d[x]+e[i].p;
                incf[y]=min(incf[x],z);
                pre[y]=i;
                if(!v[y]) v[y]=1,q.push(y);
            }
        }
    }
    if(d[t]==0xcfcfcfcf) return false;
    return true;
}
void update(){
    int x=t;
    while(x!=s){
        int i=pre[x];
        e[i].z-=incf[t];
        e[i^1].z+=incf[t];
        x=e[i^1].y; 
    }
    maxflow+=incf[t];
    ans+=d[t]*incf[t];
}
int n=1000;
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
int f(int x,int y){
    int k=x*x-y*y;
    int g=sqrt(k);
    if(g*g==k&&gcd(y,g)==1) return 1;
    else return 0;
}
int main()
{
    int a,b;
    cin>>a>>b;
    s=0;t=b+1;n=b;
    for(int i=a;i<=b;i++)
        add(s,i,1,0),add(i,s,0,0);
    for(int i=a+b;i<=b+b;i++)
        add(i,t,1,0),add(t,i,0,0);
    for(int i=a;i<=b;i++){
        for(int j=a;j<i;j++){
            if(f(i,j)){
                add(j,i+b,1,i+j);add(i+b,j,0,-i-j);
                add(i,j+b,1,i+j),add(j+b,i,0,-i-j);
            }
        }
    }
    while(spfa()) 
        update();
    cout<<maxflow/2<<" "<<ans/2<<endl;
    return 0;
}

 

上一篇:[BJOI2012]最多的方案


下一篇:这些SQL查询小技巧,一般人我不告诉他