复健训练 CF1709
A Three Doors
题意:三个门,每个门后面有一扇门的钥匙,手上有其中一扇钥匙,求是否能打开三扇门、
类似于一个dag的问题,求是否可以从一个起点遍历,使用任何图的算法都可以解决
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define gc getchar() 5 #define re register 6 #define int long long 7 inline int read() { 8 int x=0,f=1;char c(gc); 9 while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc; 10 while(c<='9'&&c>='0')x=x*10+c-48,c=gc; 11 return x*f; 12 } 13 14 int f[4][4]; 15 16 signed main() { 17 int T=read(); 18 while(T--) { 19 int x=read(),a=read(),b=read(),c=read(); 20 memset(f,0,sizeof(f)); 21 f[1][a]=f[1][1]=1; 22 f[2][b]=f[2][2]=1; 23 f[3][c]=f[3][3]=1; 24 for(int k=1;k<=3;++k) 25 for(int i=1;i<=3;++i) 26 for(int j=1;j<=3;++j) 27 f[i][j]=f[i][j]|(f[i][k]&f[k][j]); 28 int flag=0; 29 for(int i=1;i<=3;++i) if(!f[x][i]) flag=1; 30 if(flag) puts("NO"); 31 else puts("YES"); 32 } 33 return 0; 34 }
B Also Try Minecraft
题意:n列,每列有个高度值,每次询问从一列飞到另外一列过程中需要下降的总高度值
前缀和处理,O(1) 查询
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define gc getchar() 5 #define re register 6 #define int long long 7 inline int read() { 8 int x=0,f=1;char c(gc); 9 while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc; 10 while(c<='9'&&c>='0')x=x*10+c-48,c=gc; 11 return x*f; 12 } 13 14 const int N=2e5+10; 15 int n,m,a[N],s1[N],s2[N]; 16 17 18 signed main() { 19 n=read(),m=read(); 20 for(int i=1;i<=n;++i) { 21 a[i]=read(); 22 if(a[i]<a[i-1]) s1[i]=s1[i-1]+a[i-1]-a[i]; 23 else s1[i]=s1[i-1]; 24 } 25 for(int i=n;i>=1;--i) { 26 if(a[i]<a[i+1]) s2[i]=s2[i+1]+a[i+1]-a[i]; 27 else s2[i]=s2[i+1]; 28 } 29 while(m--) { 30 int l=read(),r=read(); 31 if(l<r) cout<<s1[r]-s1[l]<<'\n'; 32 else cout<<s2[r]-s2[l]<<'\n'; 33 } 34 return 0; 35 }
C Recover an RBS
题意:询问对于一个有部分残缺的括号序列是否有唯一填法
考虑如果结果不唯一会如何,贪心的填,在左半边全部(,右半边全部)是假如解法唯一的唯一解,那么在不满足这个唯一解的情况下最有可能出现变动的解就是把最中间的两个括号交换位置,假如这样满足,那么不唯一,否则唯一
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define gc getchar() 5 #define re register 6 #define int long long 7 inline int read() { 8 int x=0,f=1;char c(gc); 9 while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc; 10 while(c<='9'&&c>='0')x=x*10+c-48,c=gc; 11 return x*f; 12 } 13 14 const int N=2e5+10; 15 char s[N]; 16 int f[N],q[N],n; 17 18 signed main() { 19 int T=read(); 20 while(T--) { 21 scanf("%s",s+1); 22 n=strlen(s+1); 23 int ct=0,tp=0; 24 for(int i=1;i<=n;++i) { 25 if(s[i]=='(') ++ct; 26 else if(s[i]==')') --ct; 27 else q[++tp]=i; 28 } 29 if(fabs(ct)==tp) { 30 puts("YES"); 31 continue; 32 } 33 int l=(tp-ct)>>1; 34 for(int i=1;i<=l;++i) s[q[i]]='('; 35 for(int i=l+1;i<=tp;++i) s[q[i]]='('; 36 s[q[l+1]]='(',s[q[l]]=')'; 37 int flag=0;ct=0; 38 for(int i=1;i<=n;++i) { 39 if(s[i]=='(') ++ct; 40 else --ct; 41 if(ct<0) flag=1; 42 } 43 if(flag) puts("YES"); 44 else puts("NO"); 45 } 46 return 0; 47 }
D Rorororobot
题意:对于一个网格,每列有从下往上一定的高度的障碍物,求在每次必须走k步的情况下能否从一个点到达另外一个点
对于每次移动,和步数相关的只有在这个区间内最高的障碍物,可以用线段树,ST表等维护,然后判断这个过程是不是k的倍数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define gc getchar() 5 #define re register 6 #define int long long 7 inline int read() { 8 int x=0,f=1;char c(gc); 9 while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc; 10 while(c<='9'&&c>='0')x=x*10+c-48,c=gc; 11 return x*f; 12 } 13 14 const int N=2e5+10; 15 int n,a[N],xs,ys,xt,yt,k,m; 16 17 #define ls id<<1 18 #define rs id<<1|1 19 #define mid ((l+r)>>1) 20 int mx[N<<2]; 21 void pushup(int id) {mx[id]=max(mx[ls],mx[rs]);} 22 void built(int id,int l,int r) { 23 if(l==r) { 24 mx[id]=a[l]; 25 return; 26 } 27 built(ls,l,mid); 28 built(rs,mid+1,r); 29 pushup(id); 30 } 31 int query(int id,int l,int r,int L,int R) { 32 if(l>=L&&r<=R) return mx[id]; 33 if(mid>=R) return query(ls,l,mid,L,R); 34 if(mid<L) return query(rs,mid+1,r,L,R); 35 return max(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R)); 36 } 37 38 signed main() { 39 n=read();m=read(); 40 for(int i=1;i<=m;++i) a[i]=read(); 41 built(1,1,n); 42 int q=read(); 43 while(q--) { 44 ys=read(),xs=read(),yt=read(),xt=read(),k=read(); 45 if(xt<xs) swap(xs,xt),swap(ys,yt); 46 int m=query(1,1,n,xs,xt); 47 if(abs(xs-xt)%k||abs(ys-yt)%k) puts("NO"); 48 else { 49 int hi=(n-ys)/k*k+ys; 50 if(hi<=m) puts("NO"); 51 else puts("YES"); 52 } 53 } 54 return 0; 55 }
E XOR Tree
给一棵树,每个节点上有一个权值,求最少的权值修改次数,使得树上没有一条路径异或为零
(不知道为啥想到春节十二响,虽然我已经忘了这个题目)
对于一个节点,如果进行修改,直接修改成 230+x,这样对于再往上走节点相当于清空,我们考虑什么样的点需要进行修改,对于一个节点 u,v ,如果 a[lca(u,v)] ^ w[u] ^ w[v] 那么进行修改,对于一个节点,对其儿子进行判断是否存在这样的情况,如果存在那么对其修改(贪心修改最上面的),然后对这个节点清空,因为这样一来包含他的路径一定不可能出现0。操作使用启发式合并。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define gc getchar() 5 #define re register 6 #define int long long 7 inline int read() { 8 int x=0,f=1;char c(gc); 9 while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc; 10 while(c<='9'&&c>='0')x=x*10+c-48,c=gc; 11 return x*f; 12 } 13 14 const int N=2e5+10; 15 int n,a[N],hd[N],cnt,siz[N],w[N],ans; 16 struct node {int next,to;}e[N<<1]; 17 void add(int u,int v) { 18 e[++cnt]=(node){hd[u],v},hd[u]=cnt; 19 e[++cnt]=(node){hd[v],u},hd[v]=cnt; 20 } 21 #define QX(u) for(int i=hd[u],v;v=e[i].to,i;i=e[i].next) 22 23 set <int> s[N]; 24 25 void dfs(int u,int fa) { 26 siz[u]=1; 27 s[u].insert(w[u]); 28 bool flag=0; 29 QX(u) if(v^fa) { 30 w[v]=w[u]^a[v]; 31 dfs(v,u); 32 if(s[u].size()<s[v].size()) swap(s[u],s[v]); 33 for(int x:s[v]) if(s[u].find(x^a[u])!=s[u].end()) flag=1; 34 for(int x:s[v]) s[u].insert(x); 35 } 36 if(flag) { 37 s[u].clear(); 38 ++ans; 39 } 40 } 41 42 signed main() { 43 n=read(); 44 for(int i=1;i<=n;++i) a[i]=read(); 45 for(int i=1,u,v;i<n;++i) u=read(),v=read(),add(u,v); 46 dfs(1,1); 47 cout<<ans<<'\n'; 48 return 0; 49 }