bzoj2661[BeiJing wc2012]连连看
题意:
给出一个闭区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x2-y2是一个完全平方数z2,并且y与z互质,那么就可以将x和y一起消除,同时得到x+y点分数。求消除的数对尽可能多的前提下分数的最大值。
题解:
每个数拆成两个点,s和左侧点连流量为1,费用为0的边;右侧点和t连流量为1,费用为0的边。如果i,j合法,则同时向左侧i向右侧j及左侧j向右侧i连流量为1,费用为i+j的边。这道题和bzoj4514不同,因为每个数只出现一次,所以当左侧i和右侧j被消掉时,左侧j和右侧i也会在下一次消掉,其它的数就无法再和它们相消了。而bzoj4514每个数都有多个,可能一边没消尽,如果用这道题的做法就可能会出现另一个数把它已经被消掉的部分重复消掉,导致结果不刚好为正解的2倍。因此bzoj4514不能拆点,而这道题就可以拆点,答案就分别为算法跑出来的最大流和最大“费用”除以2。
代码:
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 #include <queue> 6 #define inc(i,j,k) for(int i=j;i<=k;i++) 7 #define ll long long 8 #define maxn 5000 9 #define INF 0x3fffffff 10 using namespace std; 11 12 struct e{int f,t;int c,w;int n;}; e es[2000000]; int ess,g[maxn]; 13 inline void pe(int f,int t,int c,int w){ 14 es[++ess]=(e){f,t,c,w,g[f]}; g[f]=ess; es[++ess]=(e){t,f,0,-w,g[t]}; g[t]=ess; 15 } 16 void init(){ess=-1; memset(g,-1,sizeof(g));} 17 queue <int> q; int d[maxn],cost,flow,fr[maxn]; bool inq[maxn],vis[maxn]; 18 bool spfa(int s,int t){ 19 while(! q.empty())q.pop(); memset(vis,0,sizeof(vis)); memset(inq,0,sizeof(inq)); 20 q.push(s); vis[s]=1; inq[s]=1; d[s]=0; 21 while(! q.empty()){ 22 int x=q.front(); q.pop(); inq[x]=0; 23 for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&(!vis[es[i].t]||d[es[i].t]<d[x]+es[i].w)){ 24 vis[es[i].t]=1; d[es[i].t]=d[x]+es[i].w; fr[es[i].t]=i; 25 if(!inq[es[i].t])q.push(es[i].t),inq[es[i].t]=1; 26 } 27 } 28 if(!vis[t])return 0;else return 1; 29 } 30 void advanced(int s,int t){ 31 int a=INF; for(int i=t;i!=s;i=es[fr[i]].f)a=min(a,es[fr[i]].c); flow+=a; 32 for(int i=t;i!=s;i=es[fr[i]].f)es[fr[i]].c-=a,es[fr[i]^1].c+=a,cost+=a*es[fr[i]].w; 33 } 34 void maxflowmaxcost(int s,int t){ 35 while(spfa(s,t))advanced(s,t); 36 } 37 int n,s,t,l,r; 38 int gcd(int a,int b){return b==0?a:gcd(b,a%b);} 39 bool check(int x,int y){ 40 if(x<=y)return 0; double z=sqrt(x*x-y*y); if(z!=(double)((int)z))return 0; 41 int zz=(int)z; if(gcd(y,zz)!=1)return 0; return 1; 42 } 43 int main(){ 44 scanf("%d%d",&l,&r); n=l-1; s=0; t=2*(r-l+1)+1; 45 init(); inc(i,l,r)pe(s,i-n,1,0),pe(i-n+(r-l+1),t,1,0); 46 inc(i,l,r)inc(j,l,r)if(check(i,j))pe(i-n,j-n+(r-l+1),1,i+j),pe(j-n,i-n+(r-l+1),1,i+j); maxflowmaxcost(s,t); 47 printf("%d %d",flow>>1,cost>>1); 48 return 0; 49 }
20160424