A.Vladik and Courtesynode
題目連接:http://codeforces.com/contest/811/problem/Aios
暴力算法
代碼以下:數組
1 #include <iostream> 2 using namespace std; 3 typedef long long ll; 4 ll a,b; 5 int main(void){ 6 cin>>a>>b; 7 ll t=1; 8 while(1){ 9 if(t&1)a-=t; 10 else b-=t; 11 t++; 12 if(a<0||b<0)break; 13 } 14 if(a<0)cout<<"Vladik"; 15 else cout<<"Valera"; 16 }
B.Vladik and Complicated Bookide
題目連接:http://codeforces.com/contest/811/problem/Bui
題目大意:判斷區間內第$k$大元素是否爲$x$.spa
離線+樹狀數組/主席樹模板/暴力code
看到數據範圍$10^4$,想成學校的老年機,想半天想出個$O(mlgm+mlgn)$的,結果被告知$O(nm)$暴力可過= =blog
代碼以下:ip
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 using namespace std; 5 typedef long long ll; 6 int n,m,a[10005],c[10005],f[10005]; 7 bool ans[10005]; 8 struct node{ 9 int l,r,x,id; 10 friend bool operator<(node qq,node pp){ 11 return a[qq.x]<a[pp.x]; 12 } 13 }q[10005]; 14 int lowbit(int x){ 15 return x&-x; 16 } 17 void add(int x){ 18 for(int i=x;i<=n;i+=lowbit(i)) 19 c[i]++; 20 } 21 int sum(int x){ 22 int ans=0; 23 for(int i=x;i>0;i-=lowbit(i)) 24 ans+=c[i]; 25 return ans; 26 } 27 int main(void){ 28 scanf("%d%d",&n,&m); 29 for(int i=1;i<=n;++i){ 30 scanf("%d",&a[i]); 31 f[a[i]]=i; 32 } 33 for(int i=0;i<m;++i){ 34 scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].x); 35 q[i].id=i; 36 } 37 sort(q,q+m); 38 int l=1; 39 for(int i=0;i<m;++i){ 40 int id=q[i].id; 41 while(l<a[q[i].x]){ 42 add(f[l]); 43 l++; 44 } 45 int t=sum(q[i].r)-sum(q[i].l-1); 46 if(q[i].l+t==q[i].x)ans[id]=1; 47 else ans[id]=0; 48 } 49 for(int i=0;i<m;++i){ 50 if(ans[i])printf("Yes\n"); 51 else printf("No\n"); 52 } 53 }
C.Vladik and Memorable Trip
題目連接:http://codeforces.com/contest/811/problem/C
題目大意:將一個數組劃分紅若干個不交叉的塊,要求塊外不含塊內元素,每一個塊的價值爲塊內不一樣元素的異或值,總價值爲全部塊的價值和,問最大價值。
DP
想着先區間合併再dp,而後算法錯誤...
看到數據範圍其實$O(n^2)$可過,直接dp就行了...
代碼以下:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 typedef long long ll; 7 int n,a[5005],dp[5005],r[5005]; 8 bool vis[5005],f[5005]; 9 int main(void){ 10 scanf("%d",&n); 11 for(int i=0;i<n;++i){ 12 scanf("%d",&a[i]); 13 r[a[i]]=i; 14 } 15 int ans=0; 16 for(int i=0;i<n;++i){ 17 int t=a[i]; 18 if(!vis[t]){ 19 vis[t]=1; 20 memset(f,0,sizeof(f)); 21 f[t]=1; 22 bool flag=1; 23 int temp=t; 24 int R=r[t]; 25 for(int j=i+1;j<R;++j){ 26 if(vis[a[j]]&&a[j]!=t){ 27 flag=0;break; 28 } 29 if(!f[a[j]]){ 30 temp^=a[j]; 31 R=max(R,r[a[j]]); 32 f[a[j]]=1; 33 } 34 } 35 if(flag)dp[R]=max(dp[R],temp+ans); 36 } 37 ans=max(ans,dp[i]); 38 } 39 printf("%d\n",ans); 40 }
D.Vladik and Favorite Game
題目連接:http://codeforces.com/contest/811/problem/D
題目大意:交互題,要求輸出從起點到終點的行動方向,其中左右和上下的方向可能會被改變一次。
XJB模擬
先dfs出不改變方向的狀況下的原行動方向,而後一步一步模擬便可。
代碼以下:
1 #include <cstdio> 2 using namespace std; 3 int n,m,d=-1,x,y,px,py,nx,ny; 4 char mp[105][105]; 5 char ans[10005]; 6 bool vis[105][105]; 7 void dfs(int px,int py,int k){ 8 if(mp[px][py]=='F'){ 9 d=k; 10 return; 11 } 12 int heng=0,shu=0; 13 if(px-1>=0&&mp[px-1][py]!='*')shu++; 14 if(px+1<n&&mp[px+1][py]!='*')shu++; 15 if(py-1>=0&&mp[px][py-1]!='*')heng++; 16 if(py+1<m&&mp[px][py+1]!='*')heng++; 17 if(shu>heng){ 18 if(px-1>=0&&!vis[px-1][py]&&mp[px-1][py]!='*'){ 19 vis[px-1][py]=1; 20 ans[k]='U'; 21 dfs(px-1,py,k+1); 22 if(d!=-1)return; 23 } 24 if(px+1<n&&!vis[px+1][py]&&mp[px+1][py]!='*'){ 25 vis[px+1][py]=1; 26 ans[k]='D'; 27 dfs(px+1,py,k+1); 28 if(d!=-1)return; 29 } 30 if(py-1>=0&&!vis[px][py-1]&&mp[px][py-1]!='*'){ 31 vis[px][py-1]=1; 32 ans[k]='L'; 33 dfs(px,py-1,k+1); 34 if(d!=-1)return; 35 } 36 if(py+1<m&&!vis[px][py+1]&&mp[px][py+1]!='*'){ 37 vis[px][py+1]=1; 38 ans[k]='R'; 39 dfs(px,py+1,k+1); 40 if(d!=-1)return; 41 } 42 }else{ 43 if(py-1>=0&&!vis[px][py-1]&&mp[px][py-1]!='*'){ 44 vis[px][py-1]=1; 45 ans[k]='L'; 46 dfs(px,py-1,k+1); 47 if(d!=-1)return; 48 } 49 if(py+1<m&&!vis[px][py+1]&&mp[px][py+1]!='*'){ 50 vis[px][py+1]=1; 51 ans[k]='R'; 52 dfs(px,py+1,k+1); 53 if(d!=-1)return; 54 } 55 if(px-1>=0&&!vis[px-1][py]&&mp[px-1][py]!='*'){ 56 vis[px-1][py]=1; 57 ans[k]='U'; 58 dfs(px-1,py,k+1); 59 if(d!=-1)return; 60 } 61 if(px+1<n&&!vis[px+1][py]&&mp[px+1][py]!='*'){ 62 vis[px+1][py]=1; 63 ans[k]='D'; 64 dfs(px+1,py,k+1); 65 if(d!=-1)return; 66 } 67 } 68 } 69 char another(char c){ 70 if(c=='R')return 'L'; 71 if(c=='L')return 'R'; 72 if(c=='U')return 'D'; 73 if(c=='D')return 'U'; 74 } 75 int main(void){ 76 scanf("%d%d",&n,&m); 77 for(int i=0;i<n;++i)scanf("%s",mp[i]); 78 dfs(0,0,0); 79 px=nx=0,py=ny=0; 80 bool heng=1,shu=1; 81 for(int i=0;i<d;){ 82 bool LR=ans[i]=='L'||ans[i]=='R'; 83 bool UD=ans[i]=='U'||ans[i]=='D'; 84 if(LR){ 85 if(heng)printf("%c\n",ans[i]); 86 else printf("%c\n",another(ans[i])); 87 if(ans[i]=='R')ny=py+1; 88 else ny=py-1; 89 }else{ 90 if(shu)printf("%c\n",ans[i]); 91 else printf("%c\n",another(ans[i])); 92 if(ans[i]=='D')nx=px+1; 93 else nx=px-1; 94 } 95 fflush(stdout); 96 scanf("%d%d",&x,&y);x--,y--; 97 if((x==-2&&y==-2)||mp[x][y]=='F')return 0; 98 if(x==px&&y==py){ 99 if(ans[i]=='L'&&y+1>=m)heng=0; 100 if(ans[i]=='R'&&y-1<0)heng=0; 101 if(ans[i]=='D'&&x-1<0)shu=0; 102 if(ans[i]=='U'&&x+1>=n)shu=0; 103 }else if(x!=nx||y!=ny){ 104 if(ans[i]=='R'&&y!=ny){ 105 heng=0; 106 printf("L\n"); 107 fflush(stdout); 108 scanf("%d%d",&x,&y);x--,y--; 109 } 110 if(ans[i]=='L'&&y!=ny){ 111 heng=0; 112 printf("R\n"); 113 fflush(stdout); 114 scanf("%d%d",&x,&y);x--,y--; 115 } 116 if(ans[i]=='U'&&y!=ny){ 117 shu=0; 118 printf("D\n"); 119 fflush(stdout); 120 scanf("%d%d",&x,&y);x--,y--; 121 } 122 if(ans[i]=='D'&&y!=ny){ 123 shu=0; 124 printf("U\n"); 125 fflush(stdout); 126 scanf("%d%d",&x,&y);x--,y--; 127 } 128 }else i++; 129 nx=px=x,ny=py=y; 130 } 131 }
E.Vladik and Entertaining Flags
題目連接:http://codeforces.com/contest/811/problem/E
題目大意:有一個$n \times m$的矩陣,$q$次詢問,每次詢問$l$列到$r$列圍成的圖中有多少連通塊。
線段樹+並查集
注意到$n \leqslant 10$,故能夠用線段樹維護。
每段維護從$L$列到$R$列的圖中有多少連通塊,以及$L$列及$R$列的段內數字編號(保證段內的聯通的數字編號是相同的)。
段與段合併時,只需判斷相鄰的數字是否相同,若相同且不爲同一連通塊,則合併。
查詢前,須要將段兩端的數字編號的$pre$指向本身(build操做中有可能將$pre$指向了其餘段中的數字編號;同時由於段內聯通的數字編號相同,故該操做不會改變段內數字的連通性),以後同合併操做。
複雜度$O(nmlgm+qnlgm)$.
代碼以下:
1 #include <cstdio> 2 #define lson x<<1,l,mid 3 #define rson x<<1|1,mid+1,r 4 using namespace std; 5 int n,m,q,mp[12][100005],pre[1000005],tot; 6 bool flag; 7 struct node{ 8 int num; 9 int L[12],R[12]; 10 }a[100005<<2],ans; 11 void init(int x){ 12 for(int i=0;i<=x;++i)pre[i]=i; 13 } 14 int Find(int x){ 15 return pre[x]==x?x:pre[x]=Find(pre[x]); 16 } 17 void Union(int a,int b){ 18 int x=Find(a),y=Find(b); 19 if(x!=y)pre[x]=y; 20 } 21 void push_up(int x,int mid){ 22 int l=x<<1,r=x<<1|1; 23 a[x].num=a[l].num+a[r].num; 24 for(int i=0;i<n;++i){ 25 if(mp[i][mid]==mp[i][mid+1]){ 26 if(Find(a[l].R[i])!=Find(a[r].L[i])){ 27 a[x].num--; 28 Union(a[l].R[i],a[r].L[i]); 29 } 30 } 31 } 32 for(int i=0;i<n;++i){ 33 a[x].L[i]=Find(a[l].L[i]); 34 a[x].R[i]=Find(a[r].R[i]); 35 } 36 } 37 void build(int x,int l,int r){ 38 if(l==r){ 39 a[x].num=1; 40 a[x].L[0]=a[x].R[0]=++tot; 41 for(int i=1;i<n;++i){ 42 if(mp[i][r]==mp[i-1][r]){ 43 a[x].L[i]=a[x].R[i]=tot; 44 }else{ 45 tot++,a[x].num++; 46 a[x].L[i]=a[x].R[i]=tot; 47 } 48 } 49 return; 50 } 51 int mid=(l+r)>>1; 52 build(lson); 53 build(rson); 54 push_up(x,mid); 55 } 56 void query(int x,int l,int r,int ql,int qr){ 57 if(ql<=l&&r<=qr){ 58 if(flag){ 59 flag=0; 60 ans=a[x]; 61 return; 62 }else{ 63 ans.num+=a[x].num; 64 for(int i=0;i<n;++i){ 65 pre[ans.R[i]]=ans.R[i]; 66 pre[a[x].L[i]]=a[x].L[i]; 67 pre[a[x].R[i]]=a[x].R[i]; 68 } 69 for(int i=0;i<n;++i){ 70 if(mp[i][l-1]==mp[i][l]){ 71 if(Find(ans.R[i])!=Find(a[x].L[i])){ 72 ans.num--; 73 Union(ans.R[i],a[x].L[i]); 74 } 75 } 76 } 77 for(int i=0;i<n;++i) 78 ans.R[i]=Find(a[x].R[i]); 79 return; 80 } 81 } 82 int mid=(l+r)>>1; 83 if(ql<=mid)query(lson,ql,qr); 84 if(mid<qr)query(rson,ql,qr); 85 } 86 int main(void){ 87 scanf("%d%d%d",&n,&m,&q); 88 init(n*m); 89 for(int i=0;i<n;++i) 90 for(int j=0;j<m;++j) 91 scanf("%d",&mp[i][j]); 92 build(1,0,m-1); 93 while(q--){ 94 int x,y; 95 scanf("%d%d",&x,&y);x--;y--; 96 flag=1; 97 query(1,0,m-1,x,y); 98 printf("%d\n",ans.num); 99 } 100 }