CF1385A~E
A.TPM
给出三个元素x,y,z,x表示max(a,b),y表示max(a,c),z表示max(b,c),请输出xyz。
推导后发现较大的两个元素必须一样,否则无解,然后输出两遍较小的元素,一遍较大的元素即可。
#include<bits/stdc++.h> using namespace std; const int maxn=1100; int a[3]; int main () { int t; scanf("%d",&t); while (t--) { scanf("%d%d%d",&a[0],&a[1],&a[2]); sort(a,a+3); if (a[2]==a[1]) { printf("YES\n"); printf("%d %d %d\n",a[0],a[0],a[2]); } else { printf("NO\n"); } } }
B.RPM
两个一样的排列互相插入后得到一个新序列,请你根据这个新的序列还原出原来的排列。
遍历一遍新序列,输出第一次出现的数即可。
#include<bits/stdc++.h> using namespace std; const int maxn=505; int a[maxn]; int n; int t; int main () { scanf("%d",&t); while (t--) { scanf("%d",&n); for (int i=1;i<=2*n;i++) scanf("%d",&a[i]); map<int,int> pos; vector<int> ans; for (int i=1;i<=2*n;i++) { if (pos[a[i]]==0) ans.push_back(a[i]),pos[a[i]]=1; } for (int i=0;i<ans.size();i++) printf("%d ",ans[i]); printf("\n"); } }
C.MG
给出一个序列,请你删掉它的前缀使得剩下的序列满足以下规则:
不断从开始或结束取出元素放入一个新的序列,这个序列是递增的。
用人话说就是找到这个序列最后一个峰状序列。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; int a[maxn]; int t,n; int main () { scanf("%d",&t); while (t--) { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); int ans=0; for (int i=n;i>=1;i--) { int j; for (j=i-1;j>=1;j--) if (a[j]<a[j+1]) break; int k; j++; for (k=j-1;k>=1;k--) if (a[k]>a[k+1]) break; ans=n-(i-k); break; } printf("%d\n",ans); } }
D.GS
一个好的a-字符串的定义是:前一半是a,后一半是好的(a+1)字符串,反过来也可以。现在给出一个字符串,询问最少修改多少个字符使其变成好的字符串。
考虑一次就能修改一半,对整个字符串做DFS即可,一开始想到二分去了。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; int n; int t; string s; int c[26][maxn]; int Min=1e9; void dfs (int l,int r,int wjm,int ans) { if (l>=r) { Min=min(Min,ans+r-l+1-(c[wjm][r]-c[wjm][l-1])); return; } int mid=(l+r)>>1; dfs(mid+1,r,wjm+1,ans+mid-l+1-(c[wjm][mid]-c[wjm][l-1])); dfs(l,mid,wjm+1,ans+r-mid-(c[wjm][r]-c[wjm][mid])); } int main () { scanf("%d",&t); while (t--) { scanf("%d",&n); cin>>s; for (int i=1;i<=s.length();i++) { for (int j=0;j<26;j++) { if (s[i-1]-'a'==j) c[j][i]=c[j][i-1]+1; else c[j][i]=c[j][i-1]; } } Min=1e9; dfs(1,n,0,0); /*while (l<r) { int mid=(l+r)>>1; //printf("%d %d\n",l,r); if (c[wjm][mid]-c[wjm][l-1]>c[wjm][r]-c[wjm][mid]) { ans+=mid-l+1-(c[wjm][mid]-c[wjm][l-1]); //printf("%d\n",ans); l=mid+1; } else if (c[wjm][mid]-c[wjm][l-1]<c[wjm][r]-c[wjm][mid]){ ans+=r-mid-(c[wjm][r]-c[wjm][mid]); //printf("%d\n",ans); r=mid; } else { if (c[wjm+1][mid]-c[wjm+1][l-1]<=c[wjm+1][r]-c[wjm+1][mid]) { ans+=mid-l+1-(c[wjm][mid]-c[wjm][l-1]); //printf("%d\n",ans); l=mid+1; } else { ans+=r-mid-(c[wjm][r]-c[wjm][mid]); //printf("%d\n",ans); r=mid; } } wjm++; } */ printf("%d\n",Min); } }
E.DE
给出一个图,里面有些边是确定方向的,有些边是不确定方向的,询问是否可以把不确定方向的边确定方向,使得最终的图是有向无环图。
先假定所有无向边不存在,做拓扑排序,如果本来就有环那一定无解。然后每个节点会得到一个拓扑序,对于每条不确定的边,由拓扑序小的节点连向拓扑序大的节点。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; vector<int> g[maxn]; int inDegree[maxn]; int visit[maxn]; struct node { int u,v; }edge[maxn]; int n,m; vector<int> wjm; int pos[maxn]; bool topo () { queue<int> q; for (int i=1;i<=n;i++) if (!inDegree[i]) { q.push(i),visit[i]=1; //break; } while (!q.empty()) { int u=q.front(); q.pop(); wjm.push_back(u); for (int i=0;i<g[u].size();i++) { int v=g[u][i]; if (--inDegree[v]==0) q.push(v); } } if (wjm.size()==n) return true; else return false; } int main () { int t; scanf("%d",&t); while (t--) { wjm.clear(); memset(inDegree,0,sizeof(inDegree)); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) g[i].clear(); int tot=0; for (int i=1;i<=m;i++) { int f,u,v; scanf("%d%d%d",&f,&u,&v); if (f==0) { edge[++tot].u=u; edge[tot].v=v; continue; } g[u].push_back(v); inDegree[v]++; } bool ff=topo(); if (ff==false) { printf("NO\n"); continue; } printf("YES\n"); for (int i=0;i<wjm.size();i++) pos[wjm[i]]=i; for (int i=1;i<=n;i++) { for (int j=0;j<g[i].size();j++) printf("%d %d\n",i,g[i][j]); } for (int i=1;i<=tot;i++) { int u=edge[i].u; int v=edge[i].v; if (pos[u]>pos[v]) swap(u,v); printf("%d %d\n",u,v); } } }