傳送門:
思路:先黑白染色,設白格個數為cnt0,和為sum0,黑格個數為cnt1,和為sum1,假設最後所有點都變成了x
那麼如果cnt0!=cnt1就是格仔數為奇數時
cnt0*x-sum0=cnt1*x-sum1
x=(sum0-sum1)/(cnt0-cnt1)
格仔為偶數時x沒有意義
我們就要想新的方法
格仔為偶數,那麼如果x合法,那麼x+1也會合法
這個可以構造證明,兩兩配對+1即可
所以這種情況可以二分
知道x後就可以用網路流check了
s向白格連x-num[i][j]的邊
白點向相鄰黑點連inf的邊,
黑點向t連x-num[i][j]的邊即可
#include#include#include#includetypedef long long ll;const int maxn=1610,maxm=20010;
const ll inf=1ll<<50;
const int dx=;
const int dy=;
using namespace std;
int cas,n,m,s=maxn-2,t=maxn-1,cnt0,cnt1;
int pre[maxm],now[maxn],son[maxm],tot,q[maxn+10],head,tail,dis[maxn];
ll sum0,sum1,x,val[maxm],num[45][45],maxs;
void add(int a,int b,ll c)
void ins(int a,int b,ll c)//,printf("%d %d %lld\n",a,b,c);
//0是白,即x+y為偶數的格仔,1是黑
int id(int x,int y)
void init()
}bool bfs()
} return dis[t]>0;
}ll find(int x,ll low)
if (!y) dis[x]=-1;
return res;
}bool dinic(ll lim)
}else ins(id(i,j),t,lim-num[i][j]);
ll res=0;
while (bfs()) res+=find(s,inf);
//printf("%lld %lld\n",res,flow);
return res==flow;
}void work()
else
printf("%lld\n",ans*cnt0-sum0); }}
int main()
bzoj2756 SCOI2012 奇怪的遊戲
description blinker最近喜歡上乙個奇怪的遊戲。這個遊戲在乙個 n m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰 的格仔,並使這兩個數都加上 1。現在 blinker 想知道最少多少次能使棋盤上的數都變成同乙個數,如果永遠不能變成同 乙個數則輸出 1。inp...
bzoj2756 SCOI2012 奇怪的遊戲
description blinker最近喜歡上乙個奇怪的遊戲。這個遊戲在乙個 n m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰的格仔,並使這兩個數都加上 1。現在 blinker 想知道最少多少次能使棋盤上的數都變成同乙個數,如果永遠不能變成同乙個數則輸出 1。input...
bzoj2756 SCOI2012 奇怪的遊戲
blinker最近喜歡上乙個奇怪的遊戲。這個遊戲在乙個 n m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰的格仔,並使這兩個數都加上 1。現在 blinker 想知道最少多少次能使棋盤上的數都變成同乙個數,如果永遠不能變成同乙個數則輸出 1。輸入的第一行是乙個整數t,表示輸入...