bzoj
blinker最近喜歡上乙個奇怪的遊戲。
這個遊戲在乙個 n*m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰
的格仔,並使這兩個數都加上 1。
現在 blinker 想知道最少多少次能使棋盤上的數都變成同乙個數,如果永遠不能變成同
乙個數則輸出-1。
輸入的第一行是乙個整數t,表示輸入資料有t輪遊戲組成。
每輪遊戲的第一行有兩個整數n和m, 分別代表棋盤的行數和列數。
接下來有n行,每行 m個數。
對於每個遊戲輸出最少能使遊戲結束的次數,如果永遠不能變成同乙個數則輸出-1。
2 21 2
2 33 3
1 2 3
2 3 4
4 3 2
-1【資料範圍】
對於30%的資料,保證 t<=10,1<=n,m<=8
對於100%的資料,保證 t<=10,1<=n,m<=40,所有數為正整數且小於1000000000
我竟然調了\(1h+....\)
我們假設知道了要把他們都變成\(x\)
如何檢驗\(x\)是否可行?
很明顯,棋盤黑白染色之後,永遠都是乙個黑點和乙個白點一起加一
所以黑點加的次數和白點加的次數一定相同
同樣的,我們知道乙個黑點要加多少次
現在的問題不過變成了黑點加的若干次如何分配給白點
因為只能加給鄰邊,黑白染色之後向相鄰的格仔連容量為\(inf\)的邊就行了
最後只需要檢查是否滿流即可。
當黑白格仔數量相同的時候,顯然答案可以二分
假設我們都可以加到乙個最小的\(x\)
那麼,乙個黑格仔唯一確定乙個白格仔
所有格仔就可以都加一,因此也可以得到任何乙個大於\(x\)的數
所以二分+判定即可
當黑白格仔數量不同
此時可行的\(x\)應該唯一確定
我們求出白格仔的和\(s1\),黑格仔的和\(s2\)
不妨設白格仔數量為\(c1\),黑格仔數量為\(c2\),且\(c1>c2\)
因為每一次都是乙個黑格加一,乙個白格加一
所以\(x=\frac\)
證明?算了,隨便寫一下
\[xc1-s1=xc2-s2
\]移過去除一下檢查是否可行即可。
#include#include#include#include#include#include#include#include#include#includeusing namespace std;
#define ll long long
#define rg register
#define inf (1ll<<50)
#define max 2000
inline int read()
struct linee[max<<4];
int h[max],cnt;
inline void add(int u,int v,ll w)
;h[u]=cnt++;
e[cnt]=(line);h[v]=cnt++;
}void init()
int level[max],s,t;
bool bfs()
return level[t];
}ll dfs(int u,ll flow)
if(!ret)level[u]=0;
return ret;
}ll dinic()
int n,m,a[45][45],bh[45][45];
int d[4][2]=;
ll sum1,sum2;
bool check(ll x)
}else add(bh[i][j],t,x-a[i][j]);
return dinic()==tot;
}int main()
if(sum1!=sum2)
ll l=mx,r=1ll<<35;
while(l<=r)
printf("%lld\n",l*whi-sum1);
} return 0;
}
bzoj 2756 奇怪的遊戲(最大流)
傳送門biu 對棋盤進行黑白染色。設黑格個數為num0,數值和為sum0 白格個數為num1 數值和為sum1。最後都變為x,則num0 x sum0 num1 x sum1,所以x sum0 sum1 num0 num1 當num0 num1時,可以解出 x 再用網路流驗證 當num1 num2時...
2756 SCOI2012 奇怪的遊戲
time limit 40 sec memory limit 128 mb submit 3052 solved 840 submit status discuss blinker最近喜歡上乙個奇怪的遊戲。這個遊戲在乙個 n m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰 的...
bzoj2756 SCOI2012 奇怪的遊戲
description blinker最近喜歡上乙個奇怪的遊戲。這個遊戲在乙個 n m 的棋盤上玩,每個格仔有乙個數。每次 blinker 會選擇兩個相鄰 的格仔,並使這兩個數都加上 1。現在 blinker 想知道最少多少次能使棋盤上的數都變成同乙個數,如果永遠不能變成同 乙個數則輸出 1。inp...