【杂题合集】震惊!这种生活习惯可能致癌!99%的人都有......
杂题合集
基本上都是不太难的思维题,难的我也写不出来。
标题党去死。
CF1714E Add Modulo 10
题意概述:
给出一个序列,可以给其中任意一个数加上当前它的个位数,问进行若干次操作后这个序列里的数能否全部相等。
解析:
思维题,不算难。
观察个位数,找规律:
- 个位数是 :只能是 。
- 个位数是 :。
- 个位数是 :。
- 个位数是 :。
- 个位数是 :。
- 个位数是 :。
- 个位数是 :。
- 个位数是 :。
- 个位数是 :。
- 个位数是 :。
可见,除个位数为 和 外,所有的数都可将个位数变为 。
对于个位数是 的数,就给它加上 ,此时只有其他数都与它相等,序列才合法。
对于其他数,都把它变成以 为个位数的数。注意到个位数从 再变到 ,相当于加了 。
将变化后的数列sort
一遍,判断相邻的两数之差是不是 的倍数就行了。
Code
点击查看代码
#include<cstdio> #include<algorithm> using namespace std; const int MAXN = 2e5 + 10; int t, n; int num[MAXN]; inline int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } bool Check(){ sort(num + 1, num + 1 + n); if(num[1] % 10 == 0){ if(num[n] == num[1]) return true; else return false; } for(register int i = 2; i <= n; i++){ int cut = num[i] - num[i - 1]; if(cut % 20) return false; } return true; } int main(){ t = read(); while(t--){ n = read(); for(register int i = 1; i <= n; i++){ num[i] = read(); if(num[i] % 10 != 2){ switch(num[i] % 10){ case 1 : num[i] += 1; break; case 3 : num[i] += 9; break; case 4 : num[i] += 18; break; case 5 : num[i] += 5; break; case 6 : num[i] += 6; break; case 7 : num[i] += 25; break; case 8 : num[i] += 14; break; case 9 : num[i] += 23; break; } } } if(Check()) puts("Yes"); else puts("No"); } return 0; }
CF1711B Party
题目概述:
给出一个 个点, 条边的无向图,问删去多少的点使得删去的点权最小,且留下的点组成的图中有偶数条边。输出删去的点的点权和。
解析:
如果 为偶数,不用删点。
如果 为奇数,删点的同时删掉的边要为奇数条,大力分类讨论:
- 删一个点:显然要选择一个度数为奇数的点。
- 删两个点:再度大力分类讨论:
- 删去两个相连的,且度数都为偶数的点。
- 删去两个相连的,且度数都为奇数的点。
- 删去不相连的,度数一奇一偶的点:
但是我们可以只删去那个度数为奇数的点,这样做会更优,所以这种情况一定不会有最优解。
- 删三个点:先考虑删去一个度数为奇,两个度数为偶且两两不相连的点。但这样完全可以只删去那个度数为奇的点,所以删去三个点一定不会有最优解。
所以,最优解只有可能在三种情况中出现,即删掉一个度数为奇的点、删掉有相连的两个度数都为奇的点、删掉相连的两个度数都为偶数的点。
因为 ,删去一个点的直接枚举点,删去两个点的直接枚举边即可。
Code
点击查看代码
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1e5 + 10, MAXM = 1e5 + 10; int t, n, m, ans; int unhap[MAXN]; int from[MAXM], to[MAXM], deg[MAXN]; inline void Clear(){ ans = 2147483647; memset(deg, 0, sizeof(deg)); } inline int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } int main(){ t = read(); while(t--){ Clear(); n = read(), m = read(); for(register int i = 1; i <= n; i++) unhap[i] = read(); for(register int i = 1; i <= m; i++){ int u, v; u = read(), v = read(); deg[u]++, deg[v]++; from[i] = u, to[i] = v; } if(!(m & 1)){ puts("0"); continue; } for(register int i = 1; i <= n; i++) if(deg[i] & 1) ans = min(ans, unhap[i]); for(register int i = 1; i <= m; i++){ int u = from[i], v = to[i]; if(!((deg[u] + deg[v]) & 1)) ans = min(ans, unhap[u] + unhap[v]); } printf("%d\n", ans); } return 0; }
CF1605C Dominant Character
题目概述:
给定一个由 abc
组成的字符串,找出一个最短的子串,满足 a
的数量大于 b
的数量和 c
的数量。
解析:
大力讨论:
- 串长为 ,两个
a
相邻。 - 串长为 ,所以仅当两个
a
中间隔了一个b
或c
,即abc
和aca
。 - 串长为 ,
a
的数量至少是 ,a
不能相邻,只能是abca
或acba
,不会有 个a
的情况。 - 串长为 ,
a
的数量至少是 ,则会有长为 的子串中有两个a
,不成立。 - 串长为 ,
a
的数量至少是 ,会出现长为 的子串中有两个a
,不成立。 - 串长为 ,
a
的数量至少是 ,且a
之间需要有三个不是a
的字母隔开。
之后以此类推,发现答案只可能到 ,再长的子串都能都被拆分成更短的满足要求的子串,之后枚举即可。
点击查看代码
Code
#include<cstdio> using namespace std; const int MAXN = 1e6 + 10; int t, n; char s[MAXN]; int main(){ scanf("%d", &t); while(t--){ bool flag = false; scanf("%d", &n); scanf("%s", s + 1); for(register int i = 2; i <= n && !flag; i++){ if(s[i] == 'a' && s[i - 1] == 'a'){ puts("2"); flag = true; } } if(n >= 3) for(register int i = 2; i <= n - 1 && !flag; i++){ if(s[i - 1] == 'a' && s[i + 1] == 'a'){ puts("3"); flag = true; } } if(n >= 4) for(register int i = 2; i <= n - 2 && !flag; i++){ if(s[i - 1] == 'a' && s[i + 2] == 'a' && ((s[i] == 'b' && s[i + 1] == 'c') || (s[i] == 'c' && s[i + 1] == 'b'))){ puts("4"); flag = true; } } if(n >= 7) for(register int i = 4; i <= n - 3 && !flag; i++){ if(s[i] == 'a' && s[i - 3] == 'a' && s[i + 3] == 'a'){ if(s[i - 1] == 'b' && s[i - 2] == 'b' && s[i + 1] == 'c' && s[i + 2] == 'c'){ puts("7"); flag = true; } else if(s[i - 1] == 'c' && s[i - 2] == 'c' && s[i + 1] == 'b' && s[i + 2] == 'b'){ puts("7"); flag = true; } } } if(!flag) puts("-1"); } return 0; }
CF1714G Path Prefixe
题目概述:
给你一颗以一号节点为根的树,每个节点上有两个权值,分别为 和 。记 为从根到节点 的 的前缀和,求最长的使得 的和小于等于 的前缀。
解析:
其实题目概述写啰嗦了,我的确概述不了这道题。读懂了题就很简单了。
看数据范围 ,以及题目中的最长、不大于,可以往二分上靠。
树论的话 dfs
是必不可少的,用 dfs
求出每个节点 和 的前缀和,把当前节点的 的前缀和压进栈里,本层的 dfs
结束时再把它弹出栈,就可以保证栈里的元素全部是从根节点到当前节点路径上,每个点的 的前缀和,upper_bound
一下即可求出最长的前缀。
注意开 long long
,CF Div.3 光卡 。long long
Code
点击查看代码
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int MAXN = 2e5 + 10; int t, n, cnt, top; int head[MAXN], ans[MAXN]; LL sum_a[MAXN], sum_b[MAXN]; LL stk[MAXN]; struct Edge{ int to, next, dis_a, dis_b; }e[MAXN << 1]; inline void Add(int u, int v, int a, int b){ e[++cnt].to = v; e[cnt].dis_a = a; e[cnt].dis_b = b; e[cnt].next = head[u]; head[u] = cnt; } inline int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } void dfs(int rt, int fa){ stk[++top] = sum_b[rt]; for(register int i = head[rt]; i; i = e[i].next){ int v = e[i].to; if(v == fa) continue; sum_a[v] = sum_a[rt] + e[i].dis_a; sum_b[v] = sum_b[rt] + e[i].dis_b; dfs(v, rt); } int pos = upper_bound(stk + 1, stk + 1 + top, sum_a[rt]) - stk; ans[rt] = pos - 2; top--; } void Clear(){ cnt = 0; top = 0; memset(head, 0, sizeof(head)); } int main(){ t = read(); while(t--){ Clear(); n = read(); for(register int i = 2; i <= n; i++){ int p, a, b; p = read(), a = read(), b = read(); Add(p, i, a, b); Add(i, p, a, b); } dfs(1, 0); for(register int i = 2; i <= n; i++) printf("%d ", ans[i]); puts(""); } return 0; }
CF1714F Build a Tree and That Is It
题目概述:
概不出来了自己品吧。
树是一个没有环的无向连通图,注意,在本题中,我们讨论的是无根树
现有四个整数 和 ,构建一颗满足以下条件的树:
- 包含从 到 的 个节点;
- 从节点 到节点 的距离(最短路的长度)为 ;
- 从节点 到节点 的距离为 ;
- 从节点 到节点 的距离为 。
输出满足条件的任意一棵树;若不存在,输出 NO
。
解析:
每条边的边权为 。
题目说是无根树,可以先假设它有一个根节点,设 ,, 三条互不相交的分别连接根节点和 ,, 号节点的链的长度。
然后就可得到:
只后我们移项,消元:
其中 ,, 可能为 ,代表该节点就是根节点。
至于无解的情况,显然,,, 都要 ,且,, 都应为偶数。
构造完这 条链后的树即为满足 个点之间的约束条件的最小的树,判断总的节点数 (从根节点到 ,, 号节点的链的长度就是链上的节点数,最后要加上根节点)与 的大小关系:
- ,则剩余的节点在任意节点上都不会影响树的合法性。
- ,构造结束。
- ,不合法,构造失败。
之后我们需要找出根节点是谁,若 ,, 都不为 ,我们可以让任意一个 且 的节点为根节点,这里选择了 号节点。
最后剩下的节点随便连谁都可以,这里选择接在 号节点。
Code
点击查看代码
#include<cstdio> using namespace std; int t, n, d12, d23, d31; int root, tot, d[4]; inline int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } void Build_Tree(int x){ printf("%d ", root); for(register int i = 1; i < d[x]; i++){ ++tot; printf("%d\n", tot); printf("%d ", tot); } printf("%d\n", x); } void Clear(){ tot = 0; root = 0; d[1] = d[2] = d[3] = 0; } int main(){ t = read(); while(t--){ Clear(); n = read(); d12 = read(), d23 = read(), d31 = read(); d[1] = (d12 + d31 - d23) / 2; d[2] = (d12 + d23 - d31) / 2; d[3] = (d23 + d31 - d12) / 2; if(d[1] + d[2] + d[3] + 1 > n || d[1] < 0 || d[2] < 0 || d[3] < 0){ puts("NO"); continue; } if((d12 + d31 - d23) & 1 || (d12 + d23 - d31) & 1 || (d23 + d31 - d12) & 1){ puts("NO"); continue; } puts("YES"); tot = 3; if(!d[1]) root = 1; if(!d[2]) root = 2; if(!d[3]) root = 3; if(!root){ tot = 4; root = 4; } if(1 != root) Build_Tree(1); if(2 != root) Build_Tree(2); if(3 != root) Build_Tree(3); while(tot < n) printf("3 %d\n", ++tot); } return 0; }
P7913 [CSP-S 2021] 廊桥分配
没考试,刷点历年原题。看着它是21年的T1,应该好欺负,然后想了一中午才想出来。
题目概述:
概NM,自己看。
解析:
廊桥先到先得,仅于飞机的起降顺序有关,加入第 条廊桥不会对前 条廊桥的分配产生影响。我们设 代表分配 条廊桥能停靠的国内航班数, 代表分配 条廊桥能停靠的国际航班数,可得 ,。
考虑每加入一条廊桥会影响哪些飞机。用 set
来维护当前在远机位和未降落的飞机。每加入一条廊桥,当前 set
顶端的飞机 停靠到廊桥,之后,set
中在 起飞后第一个降落的飞机 停靠到廊桥......以此类推。
直接在 set
中二分查找,记录次数,然后再把找到的飞机清出 set
(停靠过一遍廊桥即起飞),最后加入这条廊桥的贡献就是找到的飞机的次数。
Code
点击查看代码
#include<cstdio> #include<algorithm> using namespace std; const int MAXN = 1e5 + 10; int n, m1, m2, ans; int sum1[MAXN], sum2[MAXN]; struct Plane{ int st, ed; bool operator < (const Plane &a) const{ return st < a.st; } }p1[MAXN], p2[MAXN]; multiset<Plane> s1, s2; inline int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } int Get_Num(multiset<Plane> &s){ int ans = 0; auto pos = s.begin(); if(pos == s.end()) return 0; Plane p = *pos; p.st = p.ed; ++ans; s.erase(pos); while(!s.empty()){ pos = s.lower_bound(p); if(pos == s.end()) break; ++ans; p = *pos; p.st = p.ed; s.erase(pos); } return ans; } int main(){ n = read(), m1 = read(), m2 = read(); for(register int i = 1; i <= m1; i++){ p1[i].st = read(), p1[i].ed = read(); //国内航班 s1.insert(p1[i]); } for(register int i = 1; i <= m2; i++){ p2[i].st = read(), p2[i].ed = read(); //国外航班 s2.insert(p2[i]); } sort(p1 + 1, p1 + 1 + m1); sort(p2 + 1, p2 + 1 + m2); for(register int i = 1; i <= n; i++) sum1[i] = sum1[i - 1] + Get_Num(s1); for(register int i = 1; i <= n; i++) sum2[i] = sum2[i - 1] + Get_Num(s2); for(register int i = 0; i <= n; i++) ans = max(ans, sum1[i] + sum2[n - i]); printf("%d", ans); return 0; }
P2515 [HAOI2010]软件安装
边写边颓,结果一A了(坏了,我成wonder了)。
题目概述:
自己概去,语文功底不好,概不出来。
解析:
最开始当图论题打的,结果越打越不对,发现是个树上的背包问题。
首先,每个软件之间有依赖关系,即软件 只有在安装了软件 之后才能正常工作,考虑从 向 连边,最后会得到一个类似树形的关系。然后就理所应当的想到拓扑排序或者树形DP了是吧。
问题在于这个关系并不能直接构成树,每个关系(每条边)都是单向的,所以可能出现游离在外的点或环,比如 ,这时 就形成了一个独立的环。这个环要么都选,要么都不选,所以可以用tarjan缩点,把环缩成一个联通块。
缩完点之后仍然有独立的点,需要把它变成一个树状结构。考虑将所有入度为 的点和 连一条边,这样这张图就可以转化成一棵以 为根的树,然后就可以在树上跑01背包了。
设定状态 代表以 为根的子树在 的容量下能得到的最大的价值,在递归到当前节点的时候记得初始化一下DP数组就行了。为啥不讲转移?就是个普通的01背包,讲啥啊。
Code
点击查看代码
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 110, MAXM = 510; int n, m, cnt, num, tot; int head[MAXN], spa[MAXN], val[MAXN], from[MAXN], to[MAXN]; int dfn[MAXN], low[MAXN], belong[MAXN], room[MAXN], value[MAXN], in[MAXN]; int stk[MAXN], top; int dp[MAXN][MAXM]; bool vis[MAXN]; struct Edge{ int to, next; }e[MAXN << 1]; inline void Add(int u, int v){ e[++cnt].to = v; e[cnt].next = head[u]; head[u] = cnt; } inline int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } void Tarjan(int u){ dfn[u] = low[u] = ++num; stk[++top] = u; vis[u] = true; for(register int i = head[u]; i; i = e[i].next){ int v = e[i].to; if(!dfn[v]){ Tarjan(v); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]){ ++tot; int t; do{ t = stk[top--]; vis[t] = false; belong[t] = tot; room[tot] += spa[t]; value[tot] += val[t]; }while(t != u); } } void Rebuild(){ cnt = num = 0; memset(head, 0, sizeof(head)); for(register int i = 1; i <= n; i++){ int u = from[i], v = to[i]; int blu = belong[u], blv = belong[v]; if(!u) continue; if(blu != blv){ Add(blu, blv); ++in[blv]; } } for(register int i = 1; i <= tot; i++) if(!in[i]) Add(0, i); } void dfs(int rt){ for(register int i = room[rt]; i <= m; i++) dp[rt][i] = value[rt]; for(register int i = head[rt]; i; i = e[i].next){ int v = e[i].to; dfs(v); int k = m - room[rt]; for(register int i = k; i >= 0; i--) for(register int j = 0; j <= i; j++) dp[rt][i + room[rt]] = max(dp[rt][i + room[rt]], dp[v][j] + dp[rt][i + room[rt] - j]); } } int main(){ n = read(), m = read(); for(register int i = 1; i <= n; i++) spa[i] = read(); for(register int i = 1; i <= n; i++) val[i] = read(); for(register int i = 1; i <= n; i++){ int u; u = read(); if(u) Add(u, i); from[i] = u, to[i] = i; } for(register int i = 1; i <= n; i++) if(!dfn[i]) Tarjan(i); Rebuild(); dfs(0); printf("%d\n", dp[0][m]); return 0; }
以下为博客签名,与博文无关。
只要你们不停下来,那前面就一定有我。所以啊,不要停下来~
本文来自博客园,作者:TSTYFST,转载请注明原文链接:https://www.cnblogs.com/TSTYFST/p/16667186.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理