1. 程式人生 > >11.24 模擬賽

11.24 模擬賽

T1 bzoj 4730 Alice和Bob又在玩遊戲

題目大意:

Alice和Bob在玩遊戲 n個節點,m條邊(0<=m<=n-1),構成若干棵有根樹,每棵樹的根節點是該連通塊內編號最小的點

Alice和Bob輪流操作,每回合選擇一個沒有被刪除的節點x,將x及其所有祖先全部刪除,不能操作的人輸

思路:

根據博弈論的一些定理可以得到一個優秀的$n^2$做法

由$SG$定理得 每個點的$SG$函式值為$mex${子樹內一個點的SG xor 該根節點其餘兒子的SG}

因此對於每個點我們可以開一個trie樹表示這個點的SG集合

合併的時候每個子樹的¥trie$樹$xor$其餘子樹的$xor$和 然後像線段樹合併一樣合併$trie$樹即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<vector>
 8 #include<queue>
 9 #include<map>
10 #define rep(i,s,t) for(register int i=(s);i<=(t);++i)
11
#define dwn(i,s,t) for(register int i=(s);i>=(t);--i) 12 #define ren for(register int i=fst[x];i;i=nxt[i]) 13 #define Fill(x,t) memset(x,t,sizeof(x)) 14 #define ll long long 15 #define inf 2139062143 16 #define MAXN 200100 17 using namespace std; 18 inline int read() 19 { 20 int x=0,f=1;char ch=getchar();
21 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 22 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 23 return x*f; 24 } 25 int n,m,fst[MAXN],to[MAXN<<1],nxt[MAXN<<1],cnt,vis[MAXN],sg[MAXN]; 26 int ls[MAXN*20],rs[MAXN*20],tag[MAXN*20],tot,ans,sz[MAXN*20],rt[MAXN*20]; 27 const int maxDep=16; 28 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 29 void pshd(int k,int Dep) 30 { 31 if((tag[k]>>Dep)&1) swap(ls[k],rs[k]); 32 tag[k]&=((1<<Dep)-1); 33 tag[ls[k]]^=tag[k],tag[rs[k]]^=tag[k],tag[k]=0; 34 } 35 int merge(int x,int y,int Dep) 36 { 37 if(!(x*y)) return x|y; 38 pshd(x,Dep);pshd(y,Dep); 39 ls[x]=merge(ls[x],ls[y],Dep-1),rs[x]=merge(rs[x],rs[y],Dep-1); 40 return x; 41 } 42 void ins(int &x,int val,int Dep) 43 { 44 if(!x) x=++tot,sz[x]=1,ls[x]=rs[x]=tag[x]=0;if(!(~Dep)) return ; 45 pshd(x,Dep);ins((val&(1<<Dep))?rs[x]:ls[x],val,Dep-1); 46 sz[x]=sz[ls[x]]+sz[rs[x]]; 47 } 48 int mex(int x,int res=0) 49 { 50 dwn(i,maxDep,0) 51 { 52 if(sz[ls[x]]<(1<<i)) x=ls[x]; 53 else res|=(1<<i),x=rs[x]; 54 } 55 return res; 56 } 57 void dfs(int x,int fa) 58 { 59 int sum=0;vis[x]=1; 60 ren if(to[i]!=fa) {dfs(to[i],x);sum^=sg[to[i]];} 61 ren if(to[i]!=fa) {tag[rt[to[i]]]^=(sum^sg[to[i]]);rt[x]=merge(rt[x],rt[to[i]],maxDep);} 62 ins(rt[x],sum,maxDep);sg[x]=mex(rt[x]); 63 } 64 int main() 65 { 66 int T=read(); 67 while(T--) 68 { 69 n=read(),m=read(),tot=cnt=ans=0;int a,b; 70 while(m--) {a=read(),b=read();add(a,b);add(b,a);} 71 rep(i,1,n) if(!vis[i]) {dfs(i,0);ans^=sg[i];} 72 puts(ans?"Alice":"Bob"); 73 rep(i,1,n) fst[i]=vis[i]=sg[i]=rt[i]=0; 74 } 75 }
View Code

 

T2 bzoj 4731 魔法小程式

題目大意:

有這樣一段魔法的程式:(其中所有的陣列下標從0 開始,所有的除法的結果為整數,且向0取整)

現在給出陣列$c$ 求陣列$b$

思路:

相當於對每個數拆成一個K維空間的點 每一維長度不一樣 陣列$a$代表每一維的長度

$c_i$為這個K維空間內第i個點所對應多維立方體內的點權和(相當於字首和

因為一共只有m個點 所以有意義且長度大於1的點不超過$log \space m$個

因此我們可以暴力把這些維數還原回去

對於每一維 我們從m-1列舉到0 可以減去次一維的立方體的影響

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<vector>
 8 #include<queue>
 9 #include<map>
10 #define rep(i,s,t) for(register int i=(s);i<=(t);++i)
11 #define dwn(i,s,t) for(register int i=(s);i>=(t);--i)
12 #define ren for(int i=fst[x];i;i=nxt[i])
13 #define Fill(x,t) memset(x,t,sizeof(x))
14 #define ll long long
15 #define inf 2139062143
16 #define MAXN 1001000
17 using namespace std;
18 inline ll read()
19 {
20     ll x=0,f=1;char ch=getchar();
21     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
22     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
23     return x*f;
24 }
25 ll n,m,a[MAXN],c[MAXN],mul[MAXN];
26 int main()
27 {
28     n=read();printf("%d\n",n);rep(i,0,n-1) {a[i]=read();printf("%lld ",a[i]);if(a[i]==1) n--,i--;}
29     m=read();rep(i,0,m-1) c[i]=read();mul[0]=1,a[n++]=inf;int x,y;
30     rep(i,1,n-1) {mul[i]=mul[i-1]*a[i-1];if(mul[i]>m) {n=i;break;}}
31     rep(i,0,n-1)
32     {
33         x=m%mul[i],y=(m/mul[i])%a[i];
34         dwn(j,m-1,0) {if(x) x--;else x=mul[i]-1,y=y?y-1:a[i]-1;if(y) c[j]-=c[j-mul[i]];}
35     }
36     printf("\n%d\n",m);
37     rep(i,0,m-1) printf("%lld ",c[i]);
38 }
View Code

 

bzoj 4732 資料互動

這道ddp並不可做(因為甚至沒學ddp 有機會再回來