Codeforces Round #469 (Div. 2)

A. Left-handers, Right-handers and Ambidexters

  题意:有l个人擅长用左手,有r个人擅长用右手,有a个人可以选择用左手或右手。现在需要构建一个含偶数人的队伍,其中用左手和右手的人数相等,求队伍人数?

  思路:简单题

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int main()
 6 {
 7     int l, r, a;
 8     scanf("%d%d%d", &l, &r, &a);
 9     int Min = min(l, r) + a,Max=max(l,r);
10     int ans;
11     if (Min <= Max) ans = 2 * Min;
12     else ans = 2 * Max + 2*((Min - Max) / 2);
13     printf("%d
", ans);
14     return 0;
15 }
View Code

 B. Intercepted Message

  题意:有两条信息,包含相同的文件(大小一样、排列顺序一样),每个文件分成若干包按照顺序在网上传送。已知每个包的大小,求文件可能的最大数目?

  思路:从头到尾遍历,当和相同时数目+1

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int maxn = 100010;
 5 int a[maxn], b[maxn];
 6 int main()
 7 {
 8     int n, m;
 9     scanf("%d%d", &n, &m);
10     for (int i = 0; i < n; i++) scanf("%d", a + i);
11     for (int i = 0; i < m; i++) scanf("%d", b + i);
12     int ans = 0,tmpa=0,tmpb=0,i=0,j=0;
13     while (i <n||j <m)
14     {
15         if (tmpa==tmpb&&tmpa==0) tmpa += a[i++],tmpb+=b[j++] ;
16         else
17         {
18             if (tmpa < tmpb) tmpa += a[i++];
19             else if (tmpb < tmpa) tmpb += b[j++];
20         }
21         if (tmpa == tmpb)ans++, tmpa = tmpb = 0;
22     }
23     printf("%d
", ans);
24     return 0;
25 }
View Code

 C. Zebras

  题意:有一个01串,现在问能否分成k个子串(子串中0和1不一定在原串中连续),每个子串以0作为开始和结尾,0和1在串中交替。给出任意一种可行方案。

  思路:用vector模拟子串。当当前字符为‘0’时,如果有串为1结尾,0必须放在其后面,否则可以自成新串的开头;如果当前为1,则只能放在0结尾的子串后面

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<vector>
 5 using namespace std;
 6 const int maxn = 200010;
 7 char str[maxn];
 8 int num0=0, num1=0;
 9 vector<int>List[maxn];
10 int main()
11 {
12     scanf("%s", str + 1);
13     int len = strlen(str + 1);
14     for (int i = 1; i <= len; i++) if (str[i] == '0') num0++;
15     num1 = len - num0;
16     if (num1 >= num0 || str[1] == '1'||str[len]=='1') printf("-1
");
17     else
18     {
19         int curnum = 0,onenum=0;//前者表示List[0]~List[curnum-1]都是以0作为结尾的子串,后者表示List[curnum]~List[curnum+onenum-1]为1作为结尾的子串
20         for (int i = 1; i <= len; i++)
21         {
22             if (str[i] == '0')
23             {
24                 List[curnum++].push_back(i);
25                 if (onenum) onenum--;
26             }
27             else List[--curnum].push_back(i), onenum++;
28             if (curnum < 0) break;
29         }
30         if (onenum != 0) printf("-1
");
31         else
32         {
33             printf("%d
", curnum);
34             for (int i = 0; i < curnum; i++)
35             {
36                 int sz = List[i].size();
37                 printf("%d", sz);
38                 for (int j=0; j < sz; j++) printf(" %d", List[i][j]);
39                 printf("
");
40             }
41         }
42     }
43     return 0;
44 }
View Code

 D. A Leapfrog in the Array

  题意:有n个数,第i个数放在(i+1)/2的位置。每次选取位置最大的数,将其挪至其左侧与其最近的空位置,直至所有数字都在前n个位置。现在有q个询问,问所有操作过后,第qi个位置是哪个数字?

  思路:手动模拟一边可知,所有奇数位置不变,所有偶数位置按照+bias,bias/2(init:bias=n-index/2)知道加至bias为奇数为止。

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 typedef long long LL;
 5 int main()
 6 {
 7     LL n;
 8     int q;
 9     scanf("%I64d%d", &n, &q);
10     for (int i = 1; i <= q; i++)
11     {
12         LL index;
13         scanf("%I64d", &index);
14         if (index % 2 == 1) printf("%I64d
", (index + 1) / 2);
15         else
16         {
17             LL init = n - index / 2;
18             while (init % 2 == 0) index += init, init /= 2;
19             index = (index + init + 1) / 2;
20             printf("%I64d
", index);
21         }
22     }
23     return 0;
24 }
View Code

 E. Data Center Maintenance

  题意:假设一天有h个小时,有一个数据管理中心,有n个数据库,每个数据库每天有一个小时在系统升级当中。有m个人,每个人的数据会有两个备份存放在不同的数据库当中,保证每个人随时都能查到自己的数据。现在需要把若干个数据库的升级时间推后一小时,问其最小为多少?并给出是哪些数据库

  思路:如果一个人其数据的其中一个备份所在的数据库U(i,1)推迟一小时后的升级时间刚好和另一个备份所在的数据库U(i,2)的原本的升级时间相同,那么说明要么前一个数据库不升级,要么两个数据库都升级,我们从U(i,1)连一条有向边到U(i,2),表示U(i,1)升级会影响到U(i,2)。那么我们最后求出这个有向图的所有的强联通分量(当升级处于一个强联通分量中的某一个数据库升级,该强联通分量内所有的数据库都必须升级)。这些强联通分量不能有连出去的边(否则连出去的边所连向的点的所在的数据库也要升级)。我们找到一个数目最小的即可。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<cstring>
  6 using namespace std;
  7 struct edge
  8 {
  9     int to, next;
 10     edge(int tt=0,int nn=0):to(tt),next(nn){}
 11 };
 12 const int maxm = 200010;
 13 const int maxn = 100010;
 14 edge Edge[maxm];
 15 int Head[maxn];
 16 bool isinstack[maxn];//标记是否在搜索栈中
 17 int Stack[maxn];//模拟栈,搜索
 18 int Belong[maxn];//各结点属于哪一个强联通分量
 19 int Cnt[maxn];//各强联通分量节点数
 20 int DFN[maxn];//结点u第一次搜索到的序号(时间戳)
 21 int Low[maxn];////u或u的子树能够追溯到的最早的栈中节点的序号(时间戳) 
 22 int n,m,index,top;//节点数,边数,序号,栈顶
 23 int totedge;//边数
 24 int Bcnt;//强联通分量数
 25 
 26 void Init()
 27 {
 28     memset(Head, -1, sizeof(Head));
 29     totedge = 0;
 30     index = 0;
 31     top = -1;
 32     memset(DFN, 0, sizeof(DFN));
 33     memset(Low, 0, sizeof(Low));
 34     memset(Cnt, 0, sizeof(Cnt));
 35 }
 36 void addedge(int from, int to)
 37 {
 38     Edge[totedge] = edge(to, Head[from]);
 39     Head[from] = totedge++;
 40 }
 41 void Tarjan(int u)
 42 {
 43     DFN[u] = Low[u] = ++index;
 44     isinstack[u] = true;
 45     Stack[++top] = u;
 46     for (int i = Head[u]; i != -1; i = Edge[i].next)
 47     {
 48         int v = Edge[i].to;
 49         if (!DFN[v])
 50         {
 51             Tarjan(v);
 52             if (Low[v] < Low[u]) Low[u] = Low[v];
 53         }
 54         else
 55         {
 56             if (isinstack[v] && DFN[v] < Low[u]) Low[u] = DFN[v];
 57         }
 58     }
 59     if (DFN[u] == Low[u])
 60     {
 61         Bcnt++;
 62         int j;
 63         do
 64         {
 65             j = Stack[top--];
 66             isinstack[j] = false;
 67             Belong[j] = Bcnt;
 68             Cnt[Bcnt]++;
 69         } while (j != u);
 70     }
 71 }
 72 void Solve()
 73 {
 74     for (int i = 1; i <= n; i++)
 75     {//结点从1开始编号
 76         if (!DFN[i]) Tarjan(i);
 77     }
 78     int num_1 = 0;
 79     for (int i = 1; i <= n; i++) if (Belong[i] == 1) num_1++;
 80     //for (int i = 1; i <= n; i++) printf("%d ", Belong[i]);
 81     //选择一个强连通分量,要求没有指向其他分量的边(如果有,说明会影响其他data,不符合题意)
 82     bool ok[maxn];
 83     memset(ok, 0, sizeof(ok));
 84     for (int i = 1; i <= n; i++)
 85     {
 86         for (int j = Head[i]; j != -1; j = Edge[j].next)
 87         {
 88             if (Belong[Edge[j].to] != Belong[i]) ok[Belong[i]] = 1;
 89         }
 90     }
 91     int mincnt = -1,id=-1;
 92     for (int i = 1; i <= Bcnt; i++)
 93     {
 94         if (!ok[i])
 95         {
 96             if (mincnt==-1) id = i, mincnt = Cnt[i];
 97             else if (Cnt[i] < mincnt) mincnt = Cnt[i], id = i;
 98         }
 99     }
100     printf("%d
", mincnt);
101     for (int i = 1; i <= n; i++)
102     {
103         if (Belong[i] == id)
104         {
105             mincnt--;
106             if (mincnt == 0) printf("%d
", i);
107             else printf("%d ", i);
108         }
109     }
110 }
111 
112 int U[maxn];
113 int main()
114 {
115     int M, H;
116     scanf("%d%d%d", &n, &M,&H);
117     Init();
118     for (int i = 1; i <= n; i++)
119     {
120         scanf("%d", U + i);
121     }
122 
123     for (int i = 0; i < M; i++)
124     {
125         int u1, u2;
126         scanf("%d%d", &u1, &u2);
127         if ((U[u1] + 1) % H == U[u2]) addedge(u1, u2);
128         if ((U[u2] + 1) % H == U[u1]) addedge(u2, u1);
129     }
130     Solve();
131     return 0;
132 }
View Code
原文地址:https://www.cnblogs.com/ivan-count/p/8537333.html