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 }
View Code

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 }
View Code

 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 }
View Code

 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 }
View Code

 

posted @ 2016-07-29 07:43  wolf940509  阅读(161)  评论(0编辑  收藏  举报