L1-6 吃火锅
没有测试点 测 chi1 huo3 guo1 前后是否有别的数字字母
一行中出现多个,就只用加一次
L1-7 前世档案
看作二进制,y为0,n为1,二进制转十进制
L1-8 刮刮彩票
最后给出的1-8, 如果是列的话还要减去3,而不是直接用给的数字
L2-1 简单计算器
判断0的时候只有除法才判断分子为0,不是所有符号都判断
#include
using namespace std;
stack<int> s;
stack<char> t;
int calc(int x, int y, char c) {
if(c == '+') return x + y;
else if(c == '-') return x - y;
else if(c == '*') return x * y;
else if(c == '/') return x / y;
}
int main() {
int n, f = 1;
cin >> n;
for(int i = 0; i < n; ++i) {
int x; cin >> x;
s.push(x);
}
for(int i = 1; i < n; ++i) {
char x; cin >> x;
t.push(x);
}
while(!t.empty()) {
int y = s.top(); s.pop();
int x = s.top(); s.pop();
char c = t.top(); t.pop();
if(c == '/' && y == 0) {
f = 0;
printf("ERROR: %d/0\n", x);
break;
}
s.push(calc(x, y, c));
}
if(f) cout << s.top();
return 0;
}
L2-2 口罩发放
这道题确实超级费时。我当时用了50多分钟写这题,改bug,才得了16分。
身份证号码要求18位,每位都要是数字
身体状况为1的输出顺序,为输入记录的顺序
s会为0!!!,即某天可能一个口罩都不发放。所以要提前判断是否有发放名额,而不是发放完再判断口罩是否小于发放人数。
每天的口罩不用叠加之前未发放完的。即每天都是新的名额。
#include
using namespace std;
struct Node {
string nick, idnum;
int tag, h, m, id;
bool operator<(const Node c) const {
return h == c.h ? m == c.m ? id < c.id : m < c.m : h < c.h;
}
}b[1055];
vector<pair<string, string>> v;
unordered_map<string, int> mp;
set<string> st;
int main() {
int d, p;
cin >> d >> p;
for(int i = 1; i <= d; ++i) {
int t, s, cnt = 0;
scanf("%d%d", &t, &s);
for(int j = 0; j < t; ++j) {
cin >> b[j].nick >> b[j].idnum;
scanf("%d%d:%d", &b[j].tag, &b[j].h, &b[j].m);
b[j].id = j;
int flag = 1;
for(int i = 0; i < (b[j].idnum).size(); ++i) {
if(!isdigit(b[j].idnum[i])) {
flag = 0;
break;
}
}
if(!flag || (b[j].idnum).size() != 18) {
j--, t--;
continue;
}
if(b[j].tag == 1 && st.find(b[j].idnum) == st.end()) {
v.push_back({b[j].nick, b[j].idnum});
st.insert(b[j].idnum);
}
}
sort(b, b + t);
for(int j = 0; j < t && cnt < s; ++j) {
if(mp[b[j].idnum] < i) {
mp[b[j].idnum] = i + p;
cout << b[j].nick << " " << b[j].idnum << endl;
cnt++;
}
}
}
for(auto i : v) {
cout << i.first << " " << i.second << endl;
}
return 0;
}
L2-3 完全二叉树的层序遍历
比赛时我完全没思路,可能当时太瞌睡了,也可能太菜了。
刚才做了一下,秒想了一个思路,写出来20分。其实是错误的思路,测试点太水了。就是分别找左子树和右子树。但是左右子树不一定对半分,所以是错的。代码下面的注释就是错误样例。
上面的思路改着太麻烦了,然后就想别的思路。正解是按照后序遍历模拟,因为是完全二叉树,所以标记当前下标就可以了。
20分的代码
#include
using namespace std;
const int maxn = 35;
int a[maxn], cnt = 0, b[maxn];
void dfs(int a[], int len, int idx) {
if(!len) return ;
b[idx] = a[len - 1];
dfs(a, len / 2, idx * 2);
dfs(a + len / 2, len - len / 2 - 1, idx * 2 + 1);
}
int main() {
int n, f = 1;
cin >> n;
for(int i = 0; i < n; ++i) cin >> a[i];
dfs(a, n, 1);
for(int i = 1; i <= n; ++i) {
if(f) f = 0;
else putchar(' ');
cout << b[i];
}
return 0;
}
/*
9
91 85 71 2 34 10 15 55 18
10
91 85 71 86 2 34 10 15 55 18
*/
正解
#include
using namespace std;
const int maxn = 35;
int a[maxn], b[maxn], cnt = 0;
int n, f = 1;
void dfs(int idx) {
if(2 * idx <= n) {
dfs(2 * idx);
if(2 * idx + 1 <= n)
dfs(2 * idx + 1);
}
b[idx] = a[cnt++];
}
int main() {
cin >> n;
for(int i = 0; i < n; ++i) cin >> a[i];
dfs(1);
for(int i = 1; i <= n; ++i) {
if(f) f = 0;
else putchar(' ');
cout << b[i];
}
return 0;
}
L2-4 网红点打卡攻略
首先判断攻略是否包含了所有网红点,即n是否等于N
判断0和攻略的第一个点和最后一个点是否有路
有路的话,判断每两个点之间是否有通路,判断是否走过即可AC。
#include
using namespace std;
const int maxn = 2005;
int g[maxn][maxn], a[maxn], vis[maxn];
int main() {
int n, m, k;
cin >> n >> m;
while(m--) {
int x, y, w;
cin >> x >> y >> w;
g[x][y] = g[y][x] = w;
}
cin >> k;
int pos = 0, mx = 0x3f3f3f3f, mxn = 0, cnt = 0;
while(pos++ < k) {
int sum = 0, f = 0;
cin >> m;
for(int i = 1; i <= m; ++i) cin >> a[i];
if(m == n) {
memset(vis, 0 ,sizeof vis);
if(g[0][a[1]] && g[a[m]][0]) f = 1, sum = g[0][a[1]] + g[a[m]][0];
vis[0] = vis[a[1]] = 0;
for(int i = 1; i < m; ++i) {
if(g[a[i]][a[i + 1]] && !vis[a[i + 1]]) {
vis[a[i + 1]] = 1;
sum += g[a[i]][a[i + 1]];
}
else {
f = 0;
break;
}
}
}
if(f) {
cnt++;
if(mx > sum) {
mx = sum;
mxn = pos;
}
}
}
cout << cnt << endl << mxn << " " << mx;
return 0;
}
L3-1 那就别担心了
题目很容易理解,思路也很容易写出来。
从A开始用dfs来判断是否会到达B。但是要求A开始的任意一条边都要能到达B,终点可能是B能推出来的命题,但是我们不关心,只用到B就行了。
唯一需要注意的是dfs有很多重复的点,如果不记忆的话,会超时的。
#include
using namespace std;
const int maxn = 505;
vector<int> g[maxn];
int a, b, n, m, cnt = 0;
int vis[maxn];
pair<bool, int> dfs(int idx) {
if(idx == b) {
cnt++;
return {1, 1};
}
if(vis[idx]) {
cnt += vis[idx];
return {1, vis[idx]};
}
bool flag = 1, ent = 0;
for(auto i : g[idx]) {
auto t = dfs(i);
flag &= t.first;
vis[idx] += t.second;
ent = 1;
}
return {flag && ent, vis[idx]};
}
int main() {
cin >> n >> m;
while(m--) {
scanf("%d %d", &a, &b);
g[a].push_back(b);
}
cin >> a >> b;
if(dfs(a).first) {
printf("%d Yes", cnt);
}
else {
printf("%d No", cnt);
}
return 0;
}
L3-2 传送门
模拟
x下标范围到10的5次方,所以应该用x下标存。对每个x存加入传送门的y坐标,保存每个传送门的前一个传送门,和能到达的下一个传送门,根据能到达的下一个传送门O(1)的时间内计算出本x的终点x,再用O(n)的时间来计算和。
初始化,把每个x的0和10的9次方先加入。
期望时间复杂度O(nq)
15分, 超时需要优化,但是 错误的测试点不清楚哪里错了,希望能提供一下答案错误的样例。
#include
using namespace std;
const int maxn = (1e5 + 5), Y = 1e9;
struct Node {
int id, x, y;
int prepos; //前一点
int nxtpos; //后一点
int startx, endpos; // 最终位置
int bropos;
}e[maxn * 4];
struct cmp {
int pos, y;
cmp(int p, int yy) : pos(p), y(yy) {}
bool operator<(const cmp &b) const {
return y < b.y;
}
};
vector<cmp> v[maxn];
int cnt = 1, f[maxn];
void Init(int n) {
for(int i = 1; i <= n; ++i) {
f[i] = i;
e[cnt++] = {cnt - 1, i, 0, -1, cnt, i, i, cnt - 1};
e[cnt++] = {cnt - 1, i, Y, cnt - 2, -1, i, i, cnt - 1};
v[i].push_back({cnt - 2, 0});
v[i].push_back({cnt - 1, Y});
}
}
void count(int n) {
long long sum = 0;
for(int i = 1; i <= n; ++i) {
// f[i] = dfs(2 * i - 1, i);
sum += i * f[i];
}
printf("%lld\n", sum);
}
bool cmp1(cmp a, cmp b) {
return a.y < b.y;
}
int main() {
int n, q;
cin >> n >> q;
Init(n);
while(q--) {
char op;
int x1, x2, y;
scanf(" %c%d%d%d", &op, &x1, &x2, &y);
auto vpos1 = lower_bound(v[x1].begin(), v[x1].end(), cmp(-1, y));
int pos1 = vpos1 - v[x1].begin();
int pre1 = v[x1][pos1 - 1].pos, nxt1 = v[x1][pos1].pos;
auto vpos2 = lower_bound(v[x2].begin(), v[x2].end(), cmp(-1, y));
int pos2 = vpos2 - v[x2].begin();
int pre2 = v[x2][pos2 - 1].pos, nxt2 = v[x2][pos2].pos;
if(op == '+') {
e[cnt++] = {cnt - 1, x1, y, pre2, nxt1, e[pre2].startx, e[nxt1].endpos, cnt};
e[cnt++] = {cnt - 1, x2, y, pre1, nxt2, e[pre1].startx, e[nxt2].endpos, cnt - 2}; // x,y,前一点,后一点,最终
e[pre1].nxtpos = cnt - 1; e[pre1].endpos = e[cnt - 1].endpos;
e[nxt1].prepos = cnt - 2; e[nxt1].startx = e[cnt - 2].startx;
e[pre2].nxtpos = cnt - 2; e[pre2].endpos = e[cnt - 2].endpos;
e[nxt1].prepos = cnt - 1; e[nxt2].startx = e[cnt - 1].startx;
v[x1].insert(vpos1, cmp(cnt - 2, y));
v[x2].insert(vpos2, cmp(cnt - 1, y));
f[e[cnt - 2].startx] = e[cnt - 2].endpos;
f[e[cnt - 1].startx] = e[cnt - 1].endpos;
}
else {
nxt1 = v[x1][pos1 + 1].pos; nxt2 = v[x2][pos2 + 1].pos;
e[pre1].nxtpos = e[nxt1].bropos; e[nxt1].prepos = e[pre1].bropos;
e[nxt1].startx = e[e[pre1].bropos].startx;
e[pre2].nxtpos = e[nxt2].bropos; e[nxt2].prepos = e[pre2].bropos;
e[nxt2].startx = e[e[pre2].bropos].startx;
f[e[v[x1][pos1].pos].startx] = e[e[nxt2].bropos].endpos;
f[e[v[x2][pos2].pos].startx] = e[e[nxt1].bropos].endpos;
v[x1].erase(vpos1);
v[x2].erase(vpos2);
}
// for(int i = 1; i <= n; ++i) cout << f[i] << " ";
// cout << endl;
count(n);
}
return 0;
}
L3-3 可怜的复杂度
一看出题人 北京大学 吉如一 秒怂,巨佬出的题肯定不会。