1. 程式人生 > >【隊內訓練】ICPC2016大連題解

【隊內訓練】ICPC2016大連題解


A UVALive 7723 Wrestling Match(帶權並查集) 325 / 1045
B UVALive 7724 Regular Number(shift-and演算法) 34 / 296(賽後過掉)
C UVALive 7725 Game of Taking Stones(java二分) 65 / 328(賽後過掉)
D UVALive 7726 A Simple Math Problem(推公式) 363 / 1339
E UVALive 7727 Aninteresting game(樹狀陣列原理考察) 51 / 196

(賽後過掉)
F UVALive 7728 Detachment (推公式) * 242 / 878 *
G UVALive 7729 Garden of Eden(點分治) * 82 / 304*(賽後過掉)
H UVALive 7730 To begin or not to begin(簽到) 487 / 739
I UVALive 7731 Convex(簽到)**483 / 653**
J UVALive 7732 Find Small A(簽到) 479 / 952
K UVALive 7733 Guess the number 31 / 117

題解:
HIJ:sb題(J題注意2^8=256 =_=||)
A:帶權並查集
因為本題目只有兩種狀態,不是好就是壞。所以總的狀態就只有0,1兩種。
find函式回溯的時候sum[x]=(sum[x]+sum[t])%2,t是x的初始祖先節點;
在加入並查集時,fx=find_(x),fy=find_(y),當fx!=fy時sum[fy]=(sum[x]-sum[y]+1+2)%2;
當相同時需要判斷是否符合sum[x]!=sum[y],不符合說明有陣營不明確的人
另外本題還有一個注意點,有些並查集只有自己一個節點,這種情況下也是
不明確的人,所以需要用cnt陣列記錄每個並查集中節點數目。
最後一個注意點,有可能是加入並查集沒有錯誤,但是最後可能一個並查集中
有些點在好的陣營中,另外在壞的陣營中,需要將這種情況排除掉
https://paste.ubuntu.com/p/rBtqr2JWD7/

G:點分治演算法
問你有多少對(u,v),使得在此路徑上的種類數有k個
點分治就是基於樹上的節點進行分治。
點分治的本質其實是將一棵樹拆分成許多棵子樹處理,並不斷進行。
這其中有兩個部分是不變的,一個是計算重心,一個是對子樹進行路徑的計算或者記錄狀態
剩下的就是在總的dfs下,計算通過當前根節點的路徑上的資訊(一般計數題目是總體計算然後剪去合併的衝突項,有些問滿足條件的最長路徑是遍歷過程中不斷尋找最大值)
本題目一個注意點就是在計算當前子樹的滿足條件的路徑數時,為了降低複雜度
用下面這種方式,其實s0=(s0-1)&sta[i],這個操作可以實現對sta[i]的1的遍歷
比如與10010或等於11111的最小的數時1101,然後是1111,之後是11101,最後是11111
實際模擬一遍就知道怎麼回事了
https://paste.ubuntu.com/p/2dxdYph2zX/

for(int s0=sta[i];s0;s0=(s0-1)&sta[i])  res+=cou[((1<<k)-1)^s0];

D:推公式
題目給出兩個等式:
X+Y=A
LCM(X,Y)=B
我們可以看出A,B的GCD也就是X,Y的GCD
我們首先讓兩個等式同時除以GCD(A,B)
便得到:
X1+Y1=A/GCD(A,B)
X1Y1=B/GCD(A,B)
X1GCD(A,B)=X,Y1GCD(A,B)=Y
解方程求出X1,Y1,乘以GCD(A,B)即可
https://paste.ubuntu.com/p/3CJP22CBt8/
C.高精度
威佐夫博弈只要滿足

(5+1)2(MaxMin)=Min
所以只要大數+java二分高精度求出5就可以了。
https://paste.ubuntu.com/p/twsbyFXPJT/
E.樹狀陣列
首先我們要深刻理解樹狀陣列的內部原理
我們先來看一下每個數的二進位制碼和它們對應的lowbit
樹狀陣列原理
1.lowbit(i)表示i能整除的最大的2的冪次
2.i-lowbit(i)表示跳到前一個整冪次的二進位制區間
3.i+lowbit(i)表示跳到下一個包含當前區間的區間
如果知道這三個性質,
我們先來看第一問,求某兩段之間的lowbit之和,
我們首先求出sum(1,i1)再求出sum(1,j),字首和相減就可以了
現在問題變為如何求出sum(1n),我們來看性質1,我們發現我們只要知道
有多少恰好只能整除1的
有多少恰好只能整除2的
有多少恰好只能整除4的….
我們可以發現恰好整除1個數為[n/1n/2]向下取整
因為能夠整除1的只包含恰好整除1的和能夠整除2的
以此類推,我們就可以o(1)的計算出所有2的冪次的貢獻,之後就掃一遍算貢獻就可以了
單次複雜度是log的
再來看第二問,問某個數被加過幾次,想想樹狀陣列的add函式,這個問題就不難想了,每個數字只會在包含他的區間被重新新增,我們只要觀察性質三,就很容易算出第二問了!於是整個題就解決了。
https://paste.ubuntu.com/p/dTQsG8mfNh/
F.推公式
本題題意就是讓一個數拆成多個數之和,而且這些數的乘積最大,我們知道當我們拆的數越多,乘積就越大,然題意要求每個數不重複,所以我們要讓這些數儘量靠近,分下面兩種情況
1.X=Σi=2niX=9=2+3+4.2i,
2.X=Σi=2ni+k(k<=n)K