今天早上学校停电被迫放假半天,当时我可开心伤心坏了。

对,没错,下午又开始考试。。。

这大概又是哪一届学长考过的题?

T1 Pilot

题目描述

飞行大队有若干个来自各地的驾驶员,专门驾驶一种型号的飞机,这种飞机每架有两 个驾驶员,需一个正驾驶员和一个副驾驶员。由于种种原因,例如相互配合的问题,有些 驾驶员不能在同一架飞机上飞行,问如何搭配驾驶员才能使出航的飞机最多。 因为驾驶工作分工严格,两个正驾驶员或两个副驾驶员都不能同机飞行。

输入格式

第一行,两个整数 n 与 m,表示共有 n 个飞行员,其中有 m 名飞行员是正驾驶员。 下面有若干行,每行有 2 个数字 a、b。表示正驾驶员 a 和副驾驶员 b 可以同机飞行。 注:正驾驶员的编号在前,即正驾驶员的编号小于副驾驶员的编号。

输出格式

仅一行一个整数,表示最大起飞的飞机数。

样例输入

10 5

1 7

2 6

2 10

3 7

4 8

5 9

样例输出

4

数据范围与提示

2<=n<=100

分析

这道题很显然是一道二分图最大匹配问题(一个正驾驶员匹配一个副驾驶员)。(机房有大佬贪心写过了)

所以这道题我们选择使用匈牙利算法

奉上我丑陋的代码

代码

#include<bits/stdc++.h>
using namespace std;const int MAXN = 105;
const int MAXM = 2 * MAXN;int inpt()
{int x = 0, f = 1;char ch;for(ch = getchar(); (ch < '0' || ch > '9') && ch != '-'; ch = getchar());if(ch == '-'){f = -1;ch = getchar();}do{x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}while(ch >= '0' && ch <= '9');return x * f;
}int n, m;int hd[MAXN], nxt[MAXM], to[MAXM], tot = 0;
void Add(int x, int y)
{nxt[++tot] = hd[x];hd[x] = tot;to[tot] = y;
}bool vis[MAXN];
int mat[MAXN], ans = 0;
bool Match(int x)
{vis[x] = true;for(int i = hd[x]; i; i = nxt[i]){int y = to[i];if(vis[y]) continue;vis[y] = true;if(!mat[y] || Match(mat[y])){mat[y] = x;return true;}}return false;
}int main()
{freopen("pilot.in", "r", stdin);freopen("pilot.out", "w", stdout);n = inpt(), m = inpt();int xx, yy;while(cin >> xx >> yy){Add(xx, yy);Add(yy, xx);}for(int i = 1; i <= m; i++){memset(vis, 0, sizeof(vis));if(Match(i)) ans++;}printf("%d", ans);fclose(stdin);fclose(stdout);return 0;
}

T2 Sequence

题目描述

给定正整数序列 x1~xn,以下递增子序列均为非严格递增。

1. 计算其最长递增子序列的长度 s 。

2. 计算从给定的序列中最多可取出多少个长度为 s 的递增子序列。

3. 如果允许在取出的序列中多次使用 x1 和 xn,则从给定序列中最多可取 出多少个长度为 s的递增子序列。

输入格式

文件第 1 行有 1 个正整数 ,表示给定序列的长度。接下来的 1 行有 n 个正整数 x1~xn。

输出格式

第 1 行是最长递增子序列的长度 s。第 2 行是可取出的长度为 s 的递增子序列个数。 第 3 行是允许在取出的序列中多次使用 x1 和 xn 时可取出的长度为 的递增子序列个数。

样例输入

4

3 6 2 5

样例输出

2 2 3

数据范围与提示

1<=n<=500

洛谷题号 P2766

分析

第一个问题

很容易可以看出是DP里最基础的LIS问题。我们记下以 i 结尾的最长不下降子序列长度f [ i ]。

第二个问题

因为要求所有的位置都不能重复,所以我们类比第一题的二分图匹配,只不过这里不再是两两匹配,而是ss匹配。而二分图匹配可以用网络流做 ,那么ss匹配当然也可以。

我们假定原序列为a [ i ](虽然题面写的是x) 。

我们把每一个数当做一个树上的点, 因为每个点都只能经过一次,所以我们把每一个点 i 拆开成为两个点(我考试的时候没想到,然后就挂~掉~啦~),这里方便就记为 i 和 i + n ,在两个点上连接一条流量为1的边(当然也需要一条流量为0的反向边)。每一个点 i 连向一个点 j 有且仅当满足i > j 且 a [ i ] > a [ j ] 且 f [ i ] == f [ j ] + 1时, 因为这样才能保证是以当前位置结尾的单调不下降子序列。这里我们只需要给 i + n 和 j 之间连一条流量为 1 的边即可。

然后我们新建一个虚拟的源点 s 和汇点 t 这里假定为 0 和 2 * n + 1。源点向每一个 f [ i ] == s 的点连一条流量为 1 的边,汇点向每一个 f [ i ] == 1 的点连一条流量为 1 的边(当然这个过程可以反过来,对应的前面的步骤也需要反向)。

最后,我们从源点向汇点跑一遍最大流就可以啦,这里我们选用的是DInic算法(我考场上用的是EK,甚至还 T 了一个点)。

第三个问题

因为 a[ 1 ](x1) 和 a [ n ] (xn)可以重复使用了,所以我们只需要把原边重置,再把 1 和 1 + n ,n 和 n + n 之间的和 源点与n + n 和 汇点与1 之间的流量变为无穷大再跑一次最大流就可以了(我的代码中是重新建边的写法,考场上脑子抽了,后来直接沿用的考场代码)。

记得特判,代码里有标注

代码

奉上我丑陋的代码

#include<bits/stdc++.h>
using namespace std;const int MAXN = 505 * 2;
const int MAXM = 4 * MAXN;
const int INF = 0x3f3f3f3f;int inpt()
{int x = 0, f = 1;char ch;for(ch = getchar(); (ch < '0' || ch > '9') && ch != '-'; ch = getchar());if(ch == '-'){f = -1;ch = getchar();}do{x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}while(ch >= '0' && ch <= '9');return x * f;
}int n;
int a[MAXN];int f[MAXN], s = 1;int hd[MAXN], nxt[MAXM], to[MAXM], w[MAXM], tot = 1;
void Add(int x, int y, int z)
{nxt[++tot] = hd[x];hd[x] = tot;to[tot] = y;w[tot] = z;
}int ps, pt;int dpt[MAXN], nw[MAXM];
int MaxFlow = 0;
bool bfs()
{memset(dpt, 0, sizeof(dpt));queue<int> q;q.push(ps);dpt[ps] = 1;nw[ps] = hd[ps];while(q.size()){int x = q.front();q.pop();for(int i = hd[x]; i; i = nxt[i]){int y = to[i];if(w[i] && !dpt[y]){q.push(y);nw[y] = hd[y];dpt[y] = dpt[x] + 1;if(y == pt){return true;}}}}return false;
}
int Dinic(int x, int Flow)
{if(x == pt){return Flow;}int Rest = Flow;int i;for(i = nw[x]; i && Rest; i = nxt[i]){int y = to[i];if(w[i] && dpt[y] == dpt[x] + 1){int k = Dinic(y, min(Rest, w[i]));if(!k){dpt[y] = 0;}w[i] -= k;w[i ^ 1] += k;Rest -= k;}}nw[i] = i;return Flow - Rest;
}int ans1, ans2;int main()
{freopen("sequence.in", "r", stdin);freopen("sequence.out", "w", stdout);n = inpt();for(int i = 1; i <= n; i++){a[i] = inpt();f[i] = 1;}//LISfor(int i = 1; i <= n; i++){for(int j = 1; j <= i - 1; j++){if(a[i] >= a[j]){f[i] = max(f[i], f[j] + 1);s = max(s, f[i]);}}}//第一次memset(nw, 0, sizeof(nw));memset(dpt, 0, sizeof(dpt));for(int i = 1; i <= n; i++){Add(i, i + n, 1);Add(i + n, i, 0);}for(int i = 1; i <= n; i++){for(int j = 1; j <= i - 1; j++){if(a[i] >= a[j] && f[j] == f[i] - 1){Add(i + n, j, 1);Add(j, i + n, 0);}}}//0源 2 * n + 1 汇for(int i = 1; i <= n; i++){if(f[i] == s){Add(0, i, 1);Add(i, 0, 0); }if(f[i] == 1){Add(i + n, 2 * n + 1, 1);Add(2 * n + 1, i, 0);}}ps = 0, pt = 2 * n + 1;while(bfs()){int Flow;while(Flow = Dinic(ps, INF)){MaxFlow += Flow;}}int ans1 = MaxFlow;//第二次MaxFlow = 0;tot = 1;memset(hd, 0, sizeof(hd));//其实只在原图上在需要的位置多加一条memset(nxt, 0, sizeof(nxt));//流量为INF的边或者直接修改再跑就行 memset(to, 0, sizeof(to));//记得还得重置边?memset(w, 0, sizeof(w));memset(nw, 0, sizeof(nw));memset(dpt, 0, sizeof(dpt));//当然这里有些memset是废的for(int i = 1; i <= n; i++){if(i == 1 || i == n){Add(i, i + n, INF);//加无限边Add(i + n, i, 0);}else{Add(i, i + n, 1);Add(i + n, i, 0);}}for(int i = 1; i <= n; i++){for(int j = 1; j <= i - 1; j++){if(a[i] >= a[j] && f[j] == f[i] - 1){Add(i + n, j, 1);Add(j, i + n, 0);}}}//0源 2 * n + 1 汇for(int i = 1; i <= n; i++){if(f[i] == s){if(i == n){Add(0, i, INF);//加无限边Add(i, 0, 0);}else{Add(0, i, 1);Add(i, 0, 0); }}if(f[i] == 1){if(i == 1){Add(i + n, 2 * n + 1, INF);Add(2 * n + 1, i + n, 0);}else{Add(i + n, 2 * n + 1, 1);Add(2 * n + 1, i + n, 0);}}}while(bfs()){int Flow;while(Flow = Dinic(ps, INF)){MaxFlow += Flow;}}int ans2 = MaxFlow;if(n == 1){printf("1\n1\n1");//你猜为什么要加这一句}else{printf("%d\n%d\n%d", s, ans1, ans2);}fclose(stdin);fclose(stdout);return 0;
}
/*
4
3 6 2 56
3 6 2 5 8 7
*/

Update 2022.5.1

给大家贴一下杰哥的简洁代码

#include<bits/stdc++.h>
using namespace std;
const int INF = INT_MAX;inline int read() {char ch = getchar();int res = 0;while (ch < '0' || ch > '9') ch = getchar();while (ch >= '0' && ch <= '9') {res = (res << 3) + (res << 1) + (ch ^ 48);ch = getchar();}return res;
}int n, a[1505];
int dp[1505];struct edge {int v, flow, nxt;
}e[5000005];
int head[1505], cnt, s, t;
int dep[1505], maxflow = 0;void addedge(int u, int v, int flow) {e[cnt] = {v, flow, head[u]};head[u] = cnt++;
}int bfs() {memset(dep, 0, sizeof(dep));deque<int> q;q.push_back(s);dep[s] = 1;while (!q.empty()) {int u = q.front(); q.pop_front();for (int i = head[u]; ~i; i = e[i].nxt) {int v = e[i].v;if (dep[v] || !e[i].flow) continue;dep[v] = dep[u] + 1;q.push_back(v);}} return dep[t];
}int dfs(int u, int limit) {if (u == t || !limit) return limit;int flow = 0, k;for (int i = head[u]; ~i; i = e[i].nxt) {int v = e[i].v, w = e[i].flow;if (dep[v] == dep[u] + 1 && (k = dfs(v, min(limit, w)))) {e[i].flow -= k;e[i ^ 1].flow += k;limit -= k;flow += k;}}return flow;
}void dinic() {maxflow = 0;int k;while (bfs()) {while (k = dfs(s, INF)) maxflow += k;}
}bool cgval(int u, int v, int val) {for (int i = head[u]; ~i; i = e[i].nxt) {if (e[i].v == v) {e[i].flow = val;e[i ^ 1].flow = 0;return true;}}return false;
}int main() {
//  freopen("sequence.in", "r", stdin);
//  freopen("sequence.out", "w", stdout);memset(head, -1, sizeof(head));n = read();for (int i = 1; i <= n; i++) a[i] = read();int len = 1; dp[1] = 1;for (int i = 2; i <= n; i++) {dp[i] = 1;for (int j = 1; j <= i - 1; j++) {if (a[j] <= a[i]) dp[i] = max(dp[i], dp[j] + 1);}len = max(len, dp[i]);}printf("%d\n", len);for (int i = 1; i <= n; i++) {addedge(i, i + n, 1); addedge(i + n, i, 0); for (int j = i + 1; j <= n; j++) {if (a[i] <= a[j] && dp[j] == dp[i] + 1) {addedge(i + n, j, 1); addedge(j, i + n, 0); }}}s = 0, t = 2 * n + 1;for (int i = 1; i <= n; i++) {if (dp[i] == 1) addedge(s, i, 1), addedge(i, s, 0); if (dp[i] == len) addedge(i + n, t, 1), addedge(t, i + n, 0);}dinic();printf("%d\n", maxflow);for (int i = 0; i <= cnt; i += 2) {e[i].flow = 1;e[i ^ 1].flow = 0;}cgval(s, 1, INF);cgval(1, 1 + n, INF);cgval(n, n + n, INF);cgval(n + n, t, INF);dinic();if(n == 1) {printf("1");}else {printf("%d\n", maxflow);}}

T3 Software

题目描述

某公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程 序。每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时 又不包含另一些错误时才可以使用。一个补丁在排除某些错误的同时,往往会加入另一些 错误。 换句话说,对于每一个补丁 i ,都有 2 个与之相应的错误集合 B1(i)和 B2(i),使得仅 当软件包含 B1(i)中的所有错误,而不包含 B2(i)中的任何错误时,才可以使用补丁 i。补丁 i 将修复软件中的某些错误 F1(i),而同时加入另一些错误 F2(i)。另外,每个补丁都耗费一 定的时间。 试设计一个算法,利用公司提供的 m 个补丁程序将原软件修复成一个没有错误的软 件,并使修复后的软件耗时最少。

输入格式

文件第 1 行有 2 个正整数 n 和 m ,n 表示错误总数,m 表示补丁总数。接下来 m 行 给出了 m 个补丁的信息。每行包括一个正整数,表示运行补丁程序 i 所需时间,以及 2 个 长度为 n 的字符串,中间用一个空格符隔开。 第 1 个字符串中,如果第 k 个字符 bk 为 +,则表示第 k 个错误属于 B1(i)。若为 -, 则表示第 k 个错误属于 B2(i) ,若为 0,则第 i 个错误既不属于 B1(i) 也不属于 B2(i) ,即软 件中是否包含第 k 个错误并不影响补丁 i 的可用性。 第 2 个字符串中,如果第 k 个字符 bk 为 -,则表示第 k 个错误属于 F1(i) ,若为 +, 则表示第 k 个错误属于 F2(i),若为 0,则第 i 个错误既不属于 F1(i) 也不属于 F2(i),即软 件中是否包含第 k 个错误不会因使用补丁 i 而改变。

输出格式

输出最小耗时,如果问题无解,则输出 0。

样例输入

3 3

1 000 00-

1 00- 0-+

2 0-- -++

样例输出

8

数据范围与提示

1<=n<=20, 1<=m<=100

洛谷题号 P2761

分析

这道题我考场上瓜了,完全没有思路。

经过杰哥(机房大佬)的讲解后我如醍醐灌顶,大致思路如下:

因为错误数量小于 20 个所以我们可以考虑用二进制压缩的方式来表示状态,1 表示有错,0 表示无错,于是显然初始状态就是全是1。

因为是要求最小时间花费,所以我们可以以状态为点,以补丁包为边,以时间为边权跑最短路。一条边可以走的条件就是题面中提到的那样,我们同样可以预处理每一个补丁包的四个数组为二进制状态,这样我们就可以 O(1) 判断这条边是否能走了。这条边所连接的点就是按照题面描述处理后的状态。

这里我们选择使用的Dijsktra算法,SPFA好像也可以?

代码

奉上我丑陋的代码

#include<bits/stdc++.h>const int MAXN = 105;
const int MAXM = 25;
const int MAXK = (1 << 20) + 5;using namespace std;
int inpt()
{int x = 0, f = 1;char ch;for(ch = getchar(); (ch < '0' || ch > '9') && ch != '-'; ch = getchar());if(ch == '-'){f = -1;ch = getchar();}do{x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}while(ch >= '0' && ch <= '9');return x * f;
}int n, m;
int t[MAXN];
int b1[MAXN], b2[MAXN], f1[MAXN], f2[MAXN];
int AllWrong;struct node{int id;int val;bool operator < (node qwq)const{return val > qwq.val;}
};
int d[MAXK];
bool vis[MAXK];
void Dijkstra(int Start)
{memset(d, 0x3f, sizeof(d));memset(vis, false, sizeof(vis));d[Start] = 0;priority_queue<node> q;q.push((node){Start, 0});while(q.size()){int x = q.top().id;q.pop();if(vis[x]) continue;vis[x] = true;for(int i = 1; i <= m; i++){if((x & b1[i]) != b1[i] || x & b2[i]) continue;//判断转移是否合法int y = (x & (~f1[i])) | f2[i], z = t[i];//转移if(vis[y]) continue;if(d[y] > d[x] + z){d[y] = d[x] + z;q.push((node){y, d[y]});}} }
}int main()
{freopen("software.in", "r", stdin);freopen("software.out", "w", stdout);n = inpt(), m = inpt();AllWrong = (1 << n) - 1;//初始状态for(int i = 1; i <= m; i++){t[i] = inpt();char ch[MAXM];scanf("%s", ch + 1);for(int j = 1; j <= n; j++){if(ch[j] == '+'){b1[i] |= 1 << (j - 1);//预处理}else{if(ch[j] == '-'){b2[i] |= 1 << (j - 1);}}}scanf("%s", ch + 1);for(int j = 1; j <= n; j++){if(ch[j] == '-'){f1[i] |= 1 << (j - 1);}else{if(ch[j] == '+'){f2[i] |= 1 << (j - 1);}}} }Dijkstra(AllWrong);//最短路if(d[0] != 0x3f3f3f3f){//判断有解printf("%d", d[0]);}else{printf("0");}fclose(stdin);fclose(stdout);return 0;
}
/*
3 3
1 000 00-
1 00- 0-+
2 0-- -++
*/

好了就是这样,欢乐的一天结束了,希望我明天好运(明天好像是考数学,我感觉要遭)

有错欢迎指正(虽然大概率是没人看)

2022.4.30 五一假期快乐的第一天相关推荐

  1. 2022.5.2 五一假期痛苦的第三天

    确实,今天仍然是数学,仍然是心态爆炸,虽然通过了一番痛苦的思考把第二题给切了然后顺手拿了个机房第一(当然是因为其他大佬都爆掉了,不然也轮不到我). T1 数列 Sequence 题目描述 我们称一个长 ...

  2. 2022 CCF 非专业级别软件能力认证第一轮 (CSP-J1)入门级 C++语言试题 认证时间:2022 年 9 月 18 日 09:30~11:30

    今天的考试题,有点乱 2022 CCF 非专业级别软件能力认证第一轮 (CSP-J1)入门级 C++语言试题 认证时间:2022 年 9 月 18 日 09:30~11:30 考生注意事项:  试题 ...

  3. 互联网晚报 | 多地明确“五一”假期外地车辆轻微交通违法不予处罚;圆明园回应首次门票售罄;iPhone 15 Pro渲染图曝光...

    多地明确:"五一"假期,外地车辆轻微交通违法不予处罚 据交通发布微博,今年"五一"假期从4月29日开始至5月3日结束,共计5天.七座以下(含七座)小型客车通行收 ...

  4. rust能捏人不_不跟风出游的五一假期,武汉人到底能去哪

    放假前:终于要放假了,我要出去玩! 真正放假后:算了,难得休息,还是在家睡觉吧? 放假第二天知道你们一定还在睡懒觉,所以提前探好路,给你们找到了一个起床就能去,无需计划也能玩得很happy的地方.重点 ...

  5. 假期怕剧荒?五一假期追剧人正确打开方式

    马上就是五一假期了 趁着假期必须狠狠刷剧才是我们追剧人正确的打开方式! 追剧人,追剧魂 追剧人就是快乐多! 俗话说,吃饭不能没有饭碗,那咱们追剧也不能没有好用的追剧平台啊! 之前因为要一次性追好几部剧 ...

  6. 五一假期超越同行的减法优化法则

    五一假期快来临,我们做网站优化的也不能放松,如何在假期超越同行,这个就需要技巧,下面江西seo为大家介绍网站优化当中的减法优化法则: 减法优化方案: 了解减法优化方案之前首先我们要先了解一下相对概念这 ...

  7. 五一假期出行必备的高科技手册

    今天小编看了眼朋友圈,发现无节操的同学真是太多了,你们出去玩就好了,为啥要发图呢--各种晒,简直要虐死上班狗啊. 不过掐指一算,小编期盼已久的五一马上就要来了.抱着拯救同样期待假期出行同胞们的想法,小 ...

  8. 这个五一假期调休调的乱七八糟的

    大家好,我是飞哥! 刚刚的这个五一假期前的调休真的调的够乱,把我的计划全给打乱了. 我平时周一到周五工作生活很忙,一般早上7点30就出门了,送娃上学,然后路上顺便再送老婆去单位.到公司大概是9点到9点 ...

  9. “五一”假期出行,伴随着哪些风险

    2023年"五一"假期,文化和旅游行业复苏势头强劲,全国假日市场平稳有序.文化和旅游部数据中心测算,全国国内旅游出游合计2.74亿人次. 据交通部门数据显示,自4月27日铁路&qu ...

最新文章

  1. 一键还原奥运版_福田奥铃CTS超越版和江淮全能卡车,哪款实力更强?
  2. SpringBoot_入门-环境准备
  3. linux 中用PPA安装软件
  4. Ubuntu12环境下Thin+rails(4)+ruby(2)+nginx+mysql 配置
  5. 计算机视觉论文-2021-07-07
  6. Java判断一个数是不是素数
  7. mysql80压缩版安装_裕-安装MySQL80(压缩版)
  8. java 反射抽象_Java实现抽象工厂模式+java的反射的机制
  9. mac存储空间管理与df命令看到的剩余空间不一样的问题
  10. ofdm原理_5G进行时|5G NR物理层详解:原理、模型和组件
  11. object c中的多态
  12. MOS管功率放大器电路图与原理图文及其解析
  13. Emily姨妈家的猫
  14. JAVA快递单号查询接口对接教程【快递鸟DEMO】
  15. 在sweetalert弹出窗插件中加入html代码
  16. chfs http 文件共享服务
  17. 计算机同一优盘记录,怎么查看电脑插过U盘的记录
  18. PhotoshopCC2018软件安装教程
  19. 【RNN入门到实战】LSTM从入门到实战——实现空气质量预测
  20. 显示unc路径服务器根目录,路径解释:绝对、相对、UNC 和 URL

热门文章

  1. Linux知识点回顾之shell编程
  2. 百度小程序页面基础信息配置文档
  3. ATK-ESP8266获取时间和知心天气的天气信息
  4. PHP气缸种类,了解摩托车的心脏:汽缸材质与种类介绍
  5. easy_Maze 题解
  6. 从一则IT新闻想到的
  7. InfoWorld一周IT新闻测验 - 看看你对技术新闻的敏感程度
  8. linux系统清空缓存
  9. 蒙氏教育将好的教育带给孩子
  10. python中mod函数用法_Python 函数的介绍和用法