標籤:
3298: [USACO 2011Open]cow checkersTime Limit: 10 Sec Memory Limit: 128 MB
Submit: 65 Solved: 26
[Submit][Status][Discuss]Description
一天,Besssie準備和FJ挑戰奶牛跳棋遊戲。這個遊戲上在一個M*N(1<=M<=1,000,000;1<=N<=1,000,000)的棋盤上,
這個棋盤上在(x,y)(0<=x棋盤的左下角是(0,0)座標,棋盤的右上方是座標(M-1,N-1)。
Bessie每次都是第一個移動棋子,然後Bessie與Fj輪流移動。每一輪可以做以下三種中的一種操作:
1)在同一行,將棋子從當前位置向左移動任意格;
2)在同一列,將棋子從當前位置向下移動任意格;
3)將棋子從當前位置向下移動k格再向左移動k格(k為正整數,且要滿足移動後的棋子仍然在棋盤上)
第一個不能在棋盤上移動的人比賽算輸(因為棋子處在(0,0)點)。
共有T個回合(1<=T<=1,000),每次給出一個新起始點的座標(x,y),確定是誰贏。
Input
第1行:兩個用空格隔開的整數M和N;
第2行:一個整數T;
第3到第T+2行:兩個用空格隔開的整數x和y.
Output
第1到T行:包含“Farmer John”或者是“Bessie”,表示誰贏了這輪遊戲。
Sample Input3 3
1
1 1
Sample Output
Bessie
HINT Source
Silver
題解:實際上,一上來此題目不難想到可以通過DP(或者記憶化搜尋也行)來搞,但這樣問題來了——N,M<=1000000,顯然會爆。。。
於是只好來另闢蹊徑——(明確兩個概念: 死點:表示當某一方在還未走這一步之前如果落到了這個位置將必死無疑的點 活點:正好相反)
1.題目中說從(N-1,M-1)走到(0,0),既然這樣,我們何不看作從(0,0)走到(N-1,M-1)呢?
2.題目中說可以橫向走,可以縱向走,可以斜向走,這不就意味著只要某一點被認定為死點,則這一個點橫向、縱向、斜向上的其他點都是活點麼(很明顯如果某人走到了死點橫向、斜向、縱向上的其他點上的話,他就可以把對手一步送到死點上,結束戰鬥。。。)
3.由2可知,所有的死點必然不在同一行,同一列,同一對角線上,也就是說對於某一x或者y座標而言,其上死點的座標是唯一的
4.所以綜上所述,可以通過簡單的O(N)預先處理來實現求出每一個x座標上的死點位置,然後接下來對於每個詢問只要O(1)判斷是否相同即可
於是,我們來開始找規律:
如,黑色的斜線表示對稱軸,藍箭頭連著的是對稱的,而紅色箭頭均為與對稱軸平行的線,很明顯所有下半邊的點所在的線間隔都是1單位,這樣一來規律就很分明了——對於當前的x座標,要麼已經通過之前的某點對稱得到了結果,如果沒得到的話,那就根據上一個同側的點從斜線方向挪一格,然後對稱一下得出上半邊那個點,實現快速求解
1 /************************************************************** 2 Problem: 3298 3 User: HansBug 4 Language: Pascal 5 Result: Accepted 6 Time:72 ms 7 Memory:4132 kb 8 ****************************************************************/ 9 10 var11 i,j,k,l,m,n:longint;12 a:array[0..1000005] of longint;13 function max(x,y:longint):longint;14 begin if x>y then max:=x else max:=y; end;15 begin16 fillchar(a,sizeof(a),-1);17 a[0]:=0;l:=0; readln(n,m);18 for i:=1 to max(m,n) do19 begin if a[i]>-1 then continue;20 inc(l);a[i]:=i+l;if (i+l)<=1000005 then a[i+l]:=i; end;21 readln(n);22 for i:=1 to n do23 begin24 readln(j,k);25 if k>j then begin l:=k;k:=j;j:=l end;26 if a[j]<>k then writeln(‘Bessie‘) else writeln(‘Farmer John‘);27 end;28 end.
3298: [USACO 2011Open]cow checkers