题意
Blinker最近喜欢上一个奇怪的游戏。
这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻
的格子,并使这两个数都加上 1。
现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同
一个数则输出-1。
题解
复习了一下这个题。。
感觉还是挺好的
一个十分显然的想法就是黑白染色啊
然后假设两个颜色的格子个数分别是
a,b
a
,
b
,,和是
A,B
A
,
B
如果
a≠b
a
≠
b
设答案是ans
那么必然满足
A+a∗ans=B+b∗ans
A
+
a
∗
a
n
s
=
B
+
b
∗
a
n
s
可以得到
ans=(A−B)/(b−a)
a
n
s
=
(
A
−
B
)
/
(
b
−
a
)
直接判断就可以了
但是我们可以发现,如果a=b,那么分母就会变成0,就不可以用这个式子了
但是,我们发现,如果a=b,那么答案是满足二分性的,我们可以通过二分答案来解决这个问题
然后判是否可行,用一个网络流就可以了
以前的CODE
#include<cstdio>
#include<cstdlib>
#include<cstring>
const long long N=45*45;
const long long MAX=1LL<<50;
long long T;
long long a[45][45];
long long n,m;
long long num1,num2;//黑格子的个数 白格子的个数
long long tot1,tot2;//黑格子的总和 白格子的总和
long long ooo;
long long mymin (long long x,long long y){return x<y?x:y;}
long long mymax (long long x,long long y){return x>y?x:y;}
void init ()
{
ooo=0;
num1=num2=tot1=tot2=0;
scanf("%lld%lld",&n,&m);
for (long long u=1;u<=n;u++)
for (long long i=1;i<=m;i++)
{
scanf("%lld",&a[u][i]);
ooo=mymax(ooo,a[u][i]);
if ((u+i)%2==0) {tot1+=a[u][i];num1++;}
else {tot2+=a[u][i];num2++;}
}
}
struct qq
{
long long x,y,z;
long long other,last;
}s[20005];
long long last[N],num;
long long init1 (long long x,long long y,long long z)
{
num++;
s[num].x=x;s[num].y=y;s[num].z=z;
s[num].last=last[x];
last[x]=num;
return num;
}
void init (long long x,long long y,long long z)
{
long long Num1=init1(x,y,z),Num2=init1(y,x,0);
s[Num1].other=Num2;s[Num2].other=Num1;
return ;
}
long long st1,ed1;
long long q[N],h[N];
bool bt ()
{
memset(h,-1,sizeof(h));
long long st=1,ed=2;
q[st]=st1;h[st1]=0;
while (st!=ed)
{
long long x=q[st];
for (long long u=last[x];u!=-1;u=s[u].last)
{
long long y=s[u].y;
if (h[y]==-1&&s[u].z>0)
{
h[y]=h[x]+1;
q[ed]=y;
ed++;
}
}
st++;
}
if (h[ed1]==-1) return false;
return true;
}
long long find (long long x,long long f)
{
/*printf("%lld %lld\n",x,f);
system("pause");*/
if (x==ed1) return f;
long long s1=0;
for (long long u=last[x];u!=-1;u=s[u].last)
{
long long y=s[u].y;
if (s[u].z>0&&h[y]==(h[x]+1)&&s1<f)
{
long long tt=find(y,mymin(s[u].z,f-s1));
s1+=tt;
s[u].z-=tt;
s[s[u].other].z+=tt;
}
}
if (s1==0) h[x]=-1;
return s1;
}
bool check (long long x)//最后变为x是不是可以
{
st1=n*m+1;ed1=st1+1;
bool tf=false;
long long ans=0;
num=0;memset(last,-1,sizeof(last));
for (long long u=1;u<=n;u++)
{
for (long long i=1;i<=m;i++)
{
if ((u+i)%2==0)
{
init(st1,(u-1)*m+i,x-a[u][i]);
if (u>1) init((u-1)*m+i,(u-2)*m+i,MAX);
if (i>1) init((u-1)*m+i,(u-1)*m+i-1,MAX);
if (u<n) init((u-1)*m+i,u*m+i,MAX);
if (i<m) init((u-1)*m+i,(u-1)*m+i+1,MAX);
}
else
{
init((u-1)*m+i,ed1,x-a[u][i]);
ans=ans+x-a[u][i];
}
}
}
/*for (long long u=1;u<=num;u++)
if (s[u].z!=0)
printf("%lld %lld %lld\n",s[u].x,s[u].y,s[u].z);*/
long long tt=0;
while (bt()) tt=tt+find(st1,MAX);
if (tt==ans) return true;
return false;
}
void print (long long x)
{
long long ans=0;
for (long long u=1;u<=n;u++)
{
for (long long i=1;i<=m;i++)
{
if ((u+i)%2==0) ans=ans+x-a[u][i];
}
}
printf("%lld\n",ans);
}
void solve1 ()
{
//if (check(3)==true) printf("YES");
if (tot1!=tot2)
{
printf("-1\n");
return ;
}
long long l=ooo,r=MAX;
long long ans=-1;
while (l<=r)
{
long long mid=(l+r)/2;
//printf("%lld %lld %lld\n",l,r,mid);
if (check(mid)==true) {ans=mid;r=mid-1;}
else l=mid+1;
}
if (ans==-1) printf("-1\n");
else print(ans);
}
void solve2 ()
{
long long x=(tot1-tot2)/(num1-num2);
if (x<ooo) {printf("-1\n");return ;}
if(check(x)==true) print(x);
else printf("-1\n");
return ;
}
void solve ()
{
if (num1==num2) solve1();
else solve2();
}
int main()
{
scanf("%lld",&T);
while (T--)
{
init();
solve();
}
return 0;
}