只A出了其中的5题。。这场题意好晦涩啊,而且其他题目也有一定的难度。又是tarjan又是dinic的。。暂时先给写出来的5题做个题解吧。

  题目链接:https://vjudge.net/contest/158990#overview

 

  C题,还是一个比较水的题目,只要看懂了题意就能A出来了。

 

  E题,也是一个水题,不过要对题目的意思有一定的想象力。。从一个教室出发,先从这个教室里面拿出那个教室里面的学生写的试卷,给以后教室的学生写。然后继续进行这个步骤,最后回到第一个教室,最后再选出一些试卷给这个教室的学生做。有一个要求是每个学生都不能做自己做过的试卷,问这个要求能不能实现,如果能,给出一个任意可行的教室安排序列。很显然的,只要将教室试卷的数量从大到小排序,那么这个序列肯定是最优的。因为,下一个教室学生需要的试卷全部从上一个教室拿即可,而我们是按照从大到小排列,这个要求一定能够实现。那么只要最后回到第一个教室,这个教室的学生不做自己的试卷即可,也就是说除了这个教室以外的所有教室的试卷加起来的数目至少是这个教室的学生人数。只要满足这两个条件即可。

 

  F题,二分答案,设当前答案为mid,那么遍历比mid大的哑铃对,因为他们是无法移动的,因此判断它们的位置是否合理即可。判断位置合理的方法如下:如果说这两个哑铃不在同一行,那么肯定不行;否则判断他们之间的所有哑铃,是不是存在有哑铃的重量是大于mid的,如果存在,那么必定不行(因为没办法将其拿走),这个可以使用RMQ来进行O(1)判断。要注意的是哑铃的重量是需要离散化的,不然复杂度太高。另外需要注意的是对于map,只要进行了M[x]的访问,不论x之前知否存在,x的空间都会被开辟出来。同时,之前做过一题,似乎在同一个程序下,不同map间,如果类型是相同的,那么会共享节点信息(比如第一个map有x的信息,且M[x] = 1,但是在第二个map里面即使没有开辟x的位置,仍然存在x的节点,且M[x] = 0)。

 

  H题,题目废话了一大推,实际上很简单。给一个不超过60的n,表示出其格雷码,求两个格雷码之间的距离。方法是递归:对于两个字符串a和b如果他们的第一位是相同的,那么可以把第一位去掉,剩下的递归求距离,否则,求一个中间位置,分别求出中间位置,累和到a和b的距离即可。这样,不论是前者还是后者,都可以去掉第一位数字。以题目中的例子为例:000; 001; 011; 010; 110; 111; 101; 100。比方说求011到101的距离,实际上就是001到010的距离,加上110到111的距离再加上1(010到110的距离),而前后两个距离都可以去掉第一位数字来递归处理。那么面临的一个问题是,如何找出这个中间的位置。题目中给出了格雷码的定义,以3位为例,先按照后两位的格雷码进行排列,然后前面一半是加上0的,后面一半是把前面一半的除了第一位以外的数字全部反过来排列,再加上一个1。那么由于第一个一定是n个0,所以说n位的格雷码,最后一位一定是1后面n个0。因此我们就找到了分界的字符串。然后递归调用上面的方法即可。但是这样会T,那么我们用map实现记忆化搜索即可。最后需要注意的一个问题是,n最大是60,因此需要用64位整数来保存答案。

  

  I题,现场WA了很多发都没A出来= =。最后学习了别人代码的写法。基本思路是只需要用3个d数组分别保存点1到x的距离,x到有任意一个有第一种宝藏的地方的距离,x到任意一个有第二种宝藏的地方的距离。然后枚举这个x点,将3个距离相加,取最小的答案即可。要注意的是,如果把inf设置为0x3f3f3f3f,那么如果有3个都是inf,相加是会爆int的,这点需要注意。同时要注意,如果定义了一个d[3][N],将其以bfs(d[0])这种形式传入一个函数头为void bfs(dis[])的函数中,那么在里面memset(dis, inf, sizeof(dis));是不可行的,因为dis在这里是一个int*类型的,而在传入处d[0]的类型是(int*)[N]类型的,如果要在bfs()中写memset,需要这样写:memset(dis, inf, N * sizeof(int));。这题代码如下:

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <iostream>
 5 #include <map>
 6 #include <string>
 7 #include <queue>
 8 #define t_mid (l+r>>1)
 9 #define ls (o<<1)
10 #define rs (o<<1 | 1)
11 #define lson ls,l,t_mid
12 #define rson rs,t_mid+1,r
13 using namespace std;
14 const int N = 1e5 + 5;
15 typedef long long ll;
16 const int inf = N * 2;
17 
18 int n,m,k,a[N],b[N];
19 vector<int> G[N],g[N];
20 int d[3][N];
21 void bfs(int d[], int s[], int len)
22 {
23     queue<int> Q;
24     for(int i=1;i<=n;i++) d[i] = inf;
25     for(int i=1;i<=len;i++)
26     {
27         d[s[i]] = 0, Q.push(s[i]);
28     }
29     while(!Q.empty())
30     {
31         int u = Q.front(); Q.pop();
32         for(int i=0;i<G[u].size();i++)
33         {
34             int v = G[u][i];
35             if(d[v] > d[u] + 1)
36             {
37                 d[v] = d[u] + 1;
38                 Q.push(v);
39             }
40         }
41     }
42 }
43 
44 int main()
45 {
46     scanf("%d%d%d",&n,&m,&k);
47     for(int i=1;i<=m;i++)
48     {
49         scanf("%d",a+i);
50     }
51     for(int i=1;i<=k;i++)
52     {
53         scanf("%d",b+i);
54     }
55     for(int i=1;i<=n;i++)
56     {
57         int k;
58         scanf("%d",&k);
59         for(int j=1;j<=k;j++)
60         {
61             int v;
62             scanf("%d",&v);
63             G[i].push_back(v);
64             g[i].push_back(v);
65         }
66     }
67     int s[2];
68     s[1] = 1;
69     bfs(d[0], s, 1);
70     for(int i=1;i<=n;i++) G[i].clear();
71     for(int u=1;u<=n;u++)
72     {
73         for(int i=0;i<g[u].size();i++)
74         {
75             int v = g[u][i];
76             G[v].push_back(u);
77         }
78     }
79     bfs(d[1], a, m);
80     bfs(d[2], b, k);
81     int ans = inf;
82     for(int i=1;i<=n;i++) ans = min(ans, d[0][i] + d[1][i] + d[2][i]);
83     if(ans >= inf) printf("impossible");
84     else printf("%d\n",ans);
85     return 0;
86 }
I题