Codeforces#363 Div2
A题:
题意:给定一些数,给定一些往左走和往右走的操作,问是否能够相遇,如果相遇请求出相遇时间
分析:对于相邻两个数,如果大的往左,小的往右就能够相遇,否则不能相遇,在求出所有相遇当中的第一次相遇即可
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <vector> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <bitset> 10 #include <cmath> 11 #include <queue> 12 #include <stack> 13 using namespace std; 14 const int maxn=200050; 15 const int INF=1<<30; 16 int a[maxn]; 17 int n; 18 int main() 19 { 20 while(cin>>n) 21 { 22 string s; 23 cin>>s; 24 for(int i=0;i<n;i++) 25 cin>>a[i]; 26 int flag=0; 27 int k; 28 int minx=INF; 29 for(int i=0;i<n-1;i++) 30 { 31 int flag1=0; 32 if(s[i]=='R'&&s[i+1]=='L'&&a[i]<a[i+1]) 33 { 34 flag=1; flag1=1; 35 } 36 else if(s[i]=='L'&&s[i+1]=='R'&&a[i]>a[i+1]){ 37 flag=1; flag1=1; 38 } 39 if(flag1){ 40 int maxt=max(a[i],a[i+1]); 41 int mint=min(a[i],a[i+1]); 42 int t=(maxt-mint)/2; 43 if(t<minx) 44 minx=t; 45 } 46 } 47 if(flag) { 48 cout<<minx<<endl; 49 }else 50 { 51 cout<<"-1"<<endl; 52 } 53 } 54 return 0; 55 }
B题:
题意:*代表墙,.代表空地,一个炸弹能够炸掉横竖各一列的墙,问能否通过一枚炸弹,让所有全部变成平地
分析:这是一道Hack点极多的题,我就因为这题被Hack了,Ranting一朝回到解放前。直接模拟即可,但是要注意两种情况,一个是没有一个格子是墙壁的情况,还有一种选择放置炸弹的点不是墙壁的情况
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <vector> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <bitset> 10 #include <cmath> 11 #include <queue> 12 #include <stack> 13 using namespace std; 14 const int maxn=1100; 15 int n,m; 16 int vis[maxn],d[maxn]; 17 int main() 18 { 19 while(cin>>n>>m) 20 { 21 char s[maxn][maxn]; 22 for(int i=0;i<n;i++) 23 cin>>s[i]; 24 int flag1=0; 25 for(int i=0;i<n;i++){ 26 for(int j=0;j<m;j++){ 27 if(s[i][j]=='*'){ 28 flag1=1; break; 29 } 30 } 31 } 32 if(!flag1){ 33 cout<<"YES"<<endl; 34 cout<<"1"<<" "<<"1"<<endl; 35 continue; 36 } 37 memset(vis,0,sizeof(vis)); 38 memset(d,0,sizeof(d)); 39 int flag=0; 40 int cnt=0; 41 for(int i=0;i<n;i++) 42 { 43 for(int j=0;j<m;j++){ 44 if(s[i][j]=='*'){ 45 vis[i]++; 46 d[j]++; 47 cnt++; 48 } 49 } 50 } 51 int h,k; 52 for(int i=0;i<n;i++){ 53 for(int j=0;j<m;j++){ 54 if(s[i][j]=='*'){ 55 if(vis[i]+d[j]==cnt+1){ 56 h=i; k=j; flag=1; break; 57 } 58 }else if(s[i][j]=='.'){ 59 if(vis[i]+d[j]==cnt){ 60 h=i;k=j; flag=1; break; 61 } 62 } 63 } 64 if(flag) break; 65 } 66 if(flag){ 67 cout<<"YES"<<endl; 68 cout<<h+1<<" "<<k+1<<endl; 69 }else{ 70 cout<<"NO"<<endl; 71 } 72 } 73 return 0; 74 }
C题:
题意:0代表休息,1代表学习,2代表运动,3既可以代表学习又可以代表运动,相邻两天之间做的活不能一样,问最少休息几天
分析:赛场上没有做出来的dp,写错一个地方。dp[i][j]代表前i天,当第i天为j时的最多活动天数,当第i天为0时,必须休息,所以dp[i][0]就为前i-1天的最大值,当第i天为1或者3时,我们考虑若是工作的话,那必须从距离他最近的一个2或者0再+1,同理i为2的话也是距离他最近的一个1或者0再加1,最后减去最大工作天数即可。非常非常好的一个题目,值得回味
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <vector> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <bitset> 10 #include <cmath> 11 #include <queue> 12 #include <stack> 13 using namespace std; 14 const int maxn=110; 15 int dp[maxn][5]; 16 int a[maxn]; 17 int n; 18 int main() 19 { 20 while(cin>>n) 21 { 22 for(int i=1;i<=n;i++) 23 cin>>a[i]; 24 memset(dp,0,sizeof(dp)); 25 int mx=0; 26 for(int i=1;i<=n;i++){ 27 dp[i][0]=max(dp[i-1][0],max(dp[i-1][1],max(dp[i-1][2],dp[i-1][3]))); 28 if(a[i]==1||a[i]==3) 29 dp[i][1]=max(dp[i-1][0],dp[i-1][2])+1; 30 if(a[i]==2||a[i]==3) 31 dp[i][2]=max(dp[i-1][0],dp[i-1][1])+1; 32 int cnt=max(dp[i][0],max(dp[i][1],dp[i][2])); 33 mx=max(mx,cnt); 34 } 35 cout<<n-mx<<endl; 36 } 37 return 0; 38 }
D题:
题意:给出每个结点父结点的编号,求最小修改多少个数可以使其成为一课完整的树
分析:非常好的一个题目,我们来考虑何时是一棵树。当有环时必然不能构成一棵树,当有孤点时必然不能构成一棵树。那我们要做的就是破环,这个地方就用到了并查集,对于有环存在的两个结点,他们通过并查集查询出来的根结点必定相同,但此时有一个结点还未并入集合,因此只可能是存在环,这一点很重要,基于此,我们对每个环进行破环,孤点也可以看做一个自环。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <vector> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <bitset> 10 #include <cmath> 11 #include <queue> 12 #include <stack> 13 using namespace std; 14 const int maxn=200020; 15 int par[maxn],rankl[maxn],a[maxn]; 16 void init(int n) 17 { 18 for(int i=0;i<=n;i++){ 19 par[i]=i; 20 rankl[i]=0; 21 } 22 } 23 int findl(int x) 24 { 25 if(x==par[x]) 26 return x; 27 else 28 return par[x]=findl(par[x]); 29 } 30 void unite(int x,int y) 31 { 32 x=findl(x); 33 y=findl(y); 34 if(x==y) return; 35 if(rankl[x]<rankl[y]) 36 { 37 par[x]=y; 38 }else{ 39 par[y]=x; 40 if(rankl[x]==rankl[y]) rankl[x]++; 41 } 42 } 43 bool same(int x,int y) 44 { 45 return findl(x)==findl(y); 46 } 47 int n; 48 int main() 49 { 50 while(cin>>n) 51 { 52 int root=-1; 53 int cnt=0; 54 init(n); 55 for(int i=1;i<=n;i++) 56 { 57 scanf("%d",&a[i]); 58 if(i==a[i]) root=i; 59 } 60 for(int i=1;i<=n;i++) 61 { 62 int fx=findl(i); 63 int fy=findl(a[i]); 64 if(fx==fy&&i!=root) 65 { 66 if(root==-1) 67 root=i; 68 a[i]=root; 69 cnt++; 70 } 71 unite(fx,fy); 72 } 73 printf("%d\n",cnt); 74 for(int i=1;i<n;i++) 75 printf("%d ",a[i]); 76 printf("%d\n",a[n]); 77 } 78 return 0; 79 }