题比较简单。第一题:7min,第二题:13min,第三题:30min
第一题
题意描述
一行输入,输入是有 个数字,每个数字按照空格隔开。注意: 在输入并未给出。
然后他有个这样的题意:每个数字都是一只老鼠的编号,它们发现有一个地洞,那么这些老鼠就按照输入的数字编号钻到地洞去,然后如果碰到有重复的编号,说明这只老鼠就在以其它上面的老鼠都需要出来,然后当前编号的老鼠再跳进去,到最后所有的老鼠都要出来。问:老鼠出地洞序列
比如:输入:1 2 3 1 3 3 1,则输出为 3 2 1 3 3 1 1。 解释:首先 1 2 3 老鼠入洞,然后碰到 1 ,说明按照 3 2 1 顺序出洞,然后老鼠 1 3 再入洞;碰到 3 ,按照 3 顺序出洞,然后老鼠 3 再入洞;碰到 1,按照 3 1 顺序出洞,老鼠 1 入洞。最后都要出洞,老鼠 1 再出洞。
数据范围
题解
栈
时间复杂度
其实按照题意已经知道是栈了,洞就是一个栈,满足先进后出的规则
代码如下
#include <iostream>#include <cstring>
using namespace std;
const int N = 10010;
int n;int q[N], stk[N], tt = 0;bool in_stk[N];
int main() {
// freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout);
int x; int flag = 0; while (~scanf("%d", &x)) { if (in_stk[x]) { while (in_stk[x]) { int y = stk[-- tt]; in_stk[y] = false; if (flag ++ ) putchar(' '); printf("%d", y); } } stk[tt ++ ] = x; in_stk[x] = true; }
while (tt > 0) { if (flag ++ ) putchar(' '); printf("%d", stk[-- tt]); }}第二题
题意描述
给你一个长度为 的数组,然后一个大小为 的时间间隔。
求:在数组里面任取一个数 ,然后有一个集合 的集合,那么说明数组里面有 个数在这个集合里面,求最大的 对应的 ,如果两个 值的 相等,则求最小的
数据范围
题解
思维
时间复杂度
第一步预处理 数组, 表示数组里面的数对 取模后有多少个值为
第二步,有序离散化。因为对于重复值,只需要计算一次。同时使用哈希表记录下每个数出现了多少次
第三步,从小到大枚举有序离散化后的数组,那么对于当前值 , 一定是等于 的数量。同时在最后 要更新,减去原数组里面 的数量。因为 只是保证了取模后的值为 的数量,但是对于一个 而言,我们需要的不仅仅是取模要相等,而且要保证
WARNING因为这题 interval 可能为 0,因此需要特判
代码如下
#include <iostream>#include <cstring>#include <algorithm>#include <unordered_map>#include <vector>
using namespace std;
const int N = 100010;
int q[N];int n;int delta;int h[N];
unordered_map<int, int> um;vector<int> alls;
int main() {
// freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); scanf("%d", &n); for (int i = 0; i < n; i ++ ) { scanf("%d", &q[i]); alls.push_back(q[i]); um[q[i]] ++ ; } scanf("%d", &delta);
sort(alls.begin(), alls.end()); alls.erase(unique(alls.begin(), alls.end()), alls.end());
int m = alls.size();
if (delta == 0) { int res = 0, cnt = 0; for (auto &u: alls) if (um[u] > cnt) { res = u, cnt = um[u]; } printf("%d", res); } else { for (int i = 0; i < n; i ++ ) h[q[i] % delta] ++ ;
int res = -1, cnt = 0; for (int i = 0; i < m; i ++ ) { int t = alls[i] % delta; if (h[t] > cnt) { res = alls[i], cnt = h[t]; } h[t] -= um[alls[i]]; } printf("%d", res); } return 0;
}第三题
题目大意
给你一个长度为 的时间区间 ,表示会议从 开始, 天结束。如果小明在其中一天参加会议,那么就算小明参加了这场会议,但是小明每天最多只能参加 场会议。问:小明最多能参加多少场会议?
数据范围
题解
贪心
时间复杂度
贪心策略:按照 从小达到,若 则按照区间长度从小到大选择。如果发现 这天已经被占满了,则更新区间为 。
NOTE证明:假设贪心解为集合 ,最优解为
则有
另外,对于集合 和 中的每个区间,都有一个生效的天数,因此,分别对 和 按照生效天数排序,如果生效天数相等,则按照右端点从小到大排序。
经过排序后,贪心解存在有第一个和最优解不同的区间,如果 ,(其中 分别为贪心解和最优解的有效值,也即是区间中第几天去参加的会议。)那么现在可以将当前区间加入到 中。
如果 ,说明可以将贪心解的该区间把最优解的该区间给替换掉。
如果 ,这种情况与贪心策略相矛盾
综上,最优解能通过添加区间或者替换区间的方式变成最优解,说明
因此,
贪心证明如若有误,欢迎批评指正
这个贪心策略用优先队列维护即可。
代码如下
#include <iostream>#include <cstring>#include <queue>#include <vector>#include <unordered_map>
using namespace std;
const int N = 10010;
struct Node { int l, r, len; Node() {}; Node(int a, int b, int c) { l = a, r = b, len = c; } bool operator < (const Node& a) const { if (a.l == l) return len > a.len; return l > a.l; }};
priority_queue<Node> Q;unordered_map<int, int> cnt;
int main() {
// freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); int n, k; scanf("%d%d", &n, &k); for (int i = 0; i < n; i ++ ) { int l, r; scanf("%d%d", &l, &r); Q.push({l, r, r - l + 1}); }
int res = 0; while (Q.size()) { auto q = Q.top(); Q.pop(); // cout << q.l << ' ' << q.r << ' ' << q.len << endl; if (cnt[q.l] >= k) { if (q.l < q.r) Q.push({q.l + 1, q.r, q.len - 1}); continue; } cnt[q.l] ++ ; res ++ ; } printf("%d", res);
}TIP如果 ,,区间都是 那么,很明显这个时间复杂度就是
写在最后,第三题有 或者以下做法欢迎讨论