Codeforces 919F SG大爆搜(拓撲)

2021-08-15 13:38:21 字數 1547 閱讀 9194

題意:臭名昭著的alice和bob又要玩遊戲 :(

遊戲規則:每個人有八張卡牌,卡牌的數字可以是0、1、2、3、4,在乙個人的回合中,它可以選擇自己一張牌,再選擇對手一張牌,然後把選中的自己這個牌,替換成兩張牌之和%5,對手的牌不變。率先實現八張零牌的人獲勝。保證先手的人不會立即獲勝,存在平局情況,資料有10w組。

題解:顯然這個資料量要爆搜打表o1出答案。此題無非就是乙個單純的有向圖博弈,因此需要做的就是想幫法把當前局面壓縮起來當作點,然後用局面的轉移關係建圖連邊,然後拓撲地依據sg函式的轉移條件(所有出態局面都是先手勝->本局面先手負;存在乙個出態局面先手負->本局面先手勝)大爆搜即可。

注意到乙個人卡牌的順序是無意義的,因此可以把乙個人的狀態用5個數字(每種手牌分別有幾個,低位代表小數字)表示。我的處理是用乙個5位的10進製數字壓縮乙個人的局面(雖然可以9進製,但是10進製debug容易),先dfs把總共495種手牌情況搜出來,然後再495^2組合出每一種局面情況並做離散化對應到1-495^2個點上,然後5^2(列舉兩個人牌值)地對每個點建立邊(反向)。然後就可以拓撲了。陣列範圍都是打表打出來的,我沒學過數學,不會算 :(

這個破題我寫了3h。。。第一次寫sg爆搜。。。好多東西寫這些著就暈了。。。總之就是各種問題。。。人都寫傻了。。。菜啊。。。最後跑了700ms還好還好。。。

code:

#includeusing namespace std;

const int maxn = 500;

int d[maxn*maxn];

mapid;int idcnt;

map,int>id2;int id2cnt;

pairstatus[maxn*maxn];

int ans[maxn*maxn];

int first[maxn*maxn],nxt[1750000],des[1750000],tot;

int w[6];

int t,f;

queueq;

inline int get(int status,int x_)

void dfs(int dep,int rest,int val)

return;

}for (int i=0;i<=rest;i++)

}inline void ae(int id1,int id2)

void addedge(int fi,int se,int idd)}}

}void search()else

q.push(i);}}

while (!q.empty())

}}else}}

}}void init()

}memset(d,0,sizeof d);

for (pair,int>e:id2)

search();

}void solve()

for (int i=0;i<8;i++)

if (f)else if (res==-1)else

}elseelse if (res==-1)else

}}int main()

return 0;

}

codeforces 919D 記憶化 判環

題意 在有向圖中找出一條路徑上邊出現的相同顏色最多的,輸出這個相同顏色,有環輸出 1.思路 對於每乙個點進行記憶化搜尋,這裡的vis陣列的妙用,vis 1表示未訪問過,vis 0表示已經訪問過,vis 1表示這個節點所有子樹已經訪問過,所以可以返回值。判斷環的話出現了vis 0那麼表示有環。incl...

codeforces 1194F 組合數學

傳送門 你有n個事件,你需要按照1 n的順序完成這些事件,每個事件需要 t i 的時間完成,你現在一共有t的時間去做這些事情,每做一件事情的時候,你有0.5的概率花費 t i 的時間完成他,也有0.5的概率花費 t i 1 的時間去完成他,如果在做這個事件的時候時間花完了,你就相當於沒有做成這個事件...

codeforces 1114F 線段樹練習

這是一道用線段樹維區間值的一道題,題意很簡單,就是對於給定的乙個序列,初始時每個數的值不大於300,然後有兩中操作,乙個是對區間 l,r 的每個數乘上以個數x,乙個是詢問區間的乘積的尤拉函式值,首先對於第乙個操作顯然可以用線段樹的延遲更新來完成,對於第二個操作,我最先沒考慮資料,就想著直接維護區間的...