目录
热身赛:
1神奇的衣架2
2合法的ip
3.凸多边形?凹多边形?
正式赛
4.程序员的段子
5黄金周
6.受伤的触摸屏
7.15周年庆代表
8.九宫格输入法
9.异星崛起
10.廉价航空
11.星际旅行
12.日期博弈
13.加减法
比赛后加的题目
14.三角形
2018年的编程大赛就这样过去了,真的是一点优势没有,bfs,dijkstra和并查集我刷过的题目赵大佬都刷过,而且考了高数的,他们在学肯定印象深刻,我一年没动了,打不过打不过,现在只能万年老二了,最对不起的就是许振明和寒假的并查集了,水题还翻了3次,起手送了1h+2题
比赛的时候vs不能复制案例,freopen不安全,freopen_s不会用,忘记怎么去掉安全了,所以有的题目我案例都没打直接交了
解决方案:1.点击运行后,跳出来的命令提示符,然后右击上边框,选择编辑->粘贴
2先运行一次printf/scanf/freopen,在报错信息里找到 _CRT_SECURE_NO_DEPRECATE,复制
右键项目名(Project 那个)属性,
点c/c++->预处理器->预处理器定义右边那个,然后有个编辑,点进去,粘贴刚刚复制的,就可以用freopen了
freopen有三个参数,这里只讲怎么读文件,第一个参数是文件名,比如"test.txt",注意相对路径就要和cpp文件放一起,不然就写绝对路径,
第二个参数“r“,代表read
第三个参数stdin
然后把案例复制到test.txt里,就解决了复制不了的问题了
题目链接
题解:
lru算法,开数组,一个来存衣服的新旧程度(相当于队列),一个存在队列的位置,一个存在衣架的位置,一个存衣服在衣架的哪
如果是已经在衣架上了,就找一下衣服在队列的哪里,然后删掉,入队
如果衣架满了,就把队列第一个删了,再把新的入队
否则直接入队
快还是曾大佬快,我的是52ms,曾大佬16ms
#include
#include
int main() {
const int maxN = 10001;
//out是在衣架的位置,hanger是衣架,pos是在队列的位置,queue是队列
int out[maxN], hanger[maxN], pos[maxN], queue[maxN], n, a, b, c, t, head, rear, preClothing, prePos;
scanf("%d", &n);
while (n--) {
scanf("%d%d%d", &a, &b, &c);
head = rear = 0;
memset(out, -1, sizeof(out));
memset(hanger, 0, sizeof(hanger));
memset(pos, -1, sizeof(pos));
while (c--) {
scanf("%d", &t);
if (out[t] >= 0) {
queue[rear] = t;
for (int i = pos[t]; i < rear; ++i) {
queue[i] = queue[i + 1];
pos[queue[i]] = i;
}
}
else if (rear - head >= a) {
preClothing = queue[head];
prePos = out[preClothing];
pos[preClothing] = -1;
out[preClothing] = -1;
pos[t] = rear;
out[t] = prePos;
queue[rear] = t;
hanger[prePos] = t;
++head;
++rear;
}
else {
out[t] = rear;
pos[t] = rear;
hanger[rear] = t;
queue[rear] = t;
++rear;
}
}
for (int i = 0; i
这题。。。打的有心理阴影了,因为当时是一个3分钟2000b的人出的题目,而且有个00.0.0.0他没点明,我,大柱,曾大佬,柚子好像都崩了,第二天才改的,然后蔡老改到了oj,这题其实是个水题
#include
#include
using namespace std;
bool check(const string &s) {
if (s.size() == 1 && "0" <= s && s <= "9" || s.size() == 2 && "10" <= s && s <= "99" || s.size() == 3 && "100" <= s && s <= "255")return true;
return false;
}
bool isLeagal(const string &s) {
int pre = -1, cnt = 0;
for (int i = 0; i= '0'&&s[i] <= '9')continue;
if (s[i] == '.') {
++cnt;
if (cnt>3 || !check(s.substr(pre + 1, i - pre - 1)))return false;
pre = i;
}
else return false;
}
if (cnt != 3 || !check(s.substr(pre + 1, s.size() - pre - 1)))return false;
return true;
}
int main() {
int n;
string s;
scanf("%d", &n);
while (n--) {
cin >> s;
printf("%s\n", isLeagal(s) ? "legal" : "illegal");
}
return 0;
}
用叉积,沿着边缘走一圈,每次顺序地选三个点 i<=j<=k然后i->j组成一个向量,i->k组成一个,叉积<0就是凹的
#include
const int maxN = 100;
int x[maxN], y[maxN];
bool multiplicationCross(const int &a, const int &b, const int &c) {
return (x[b] - x[a])*(c[y] - a[y]) - (y[b] - y[a])*(x[c] - x[a]) >= 0;
}
int main() {
bool flag;
int n, T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 0; i < n; ++i)scanf("%d%d", &x[i], &y[i]);
flag = true;
for (int i = 0; i < n; ++i) {
if (!multiplicationCross(i, (i + 1) % n, (i + 2) % n)) {
flag = false;
break;
}
}
puts(flag ? "convex" : "concave");
}
return 0;
}
作为比赛的第一题本来应该是送分的,我起手翻车3次,送了1h,其实直接慢慢乘上去,>=就停。
#include
#include
int main() {
int n, a, t;
scanf("%d", &n);
while (n--) {
scanf("%d", &a);
t = pow(2, (int)log2(a));
printf("%d\n", t >= a ? t : t * 2);
}
return 0;
}
其实就是排序+贪心
比赛的时候我第一反应dp,看到他们都A了,我就想肯定是贪心,严格证明了一下确实是贪心,然后就A了
#include
#include
int main() {
int a[1000], n, m, p;
scanf("%d", &n);
while (n--) {
scanf("%d%d", &m, &p);
for (int i = 0; i < p; ++i)scanf("%d", &a[i]);
std::sort(a, a + p);
int pre = 0, cnt = 1;
for (int i = 1; i < p; ++i) {
if (pre + a[i] + 1 > m)break;
pre += a[i] + 1;
++cnt;
}
printf("%d\n", cnt);
}
return 0;
}
当时比赛死活想不起来,毕竟一年没用了,对不起许振明
4点共面,混合积=0或者线性相关的行列式=0
#include
int main() {
int n, x[4], y[4], z[4], r[3][3];
scanf("%d", &n);
while (n--) {
scanf("%d%d%d", &x[0], &y[0], &z[0]);
for (int i = 1; i <= 3; ++i) {
scanf("%d%d%d", &x[i], &y[i], &z[i]);
r[i - 1][0] = x[i] - x[0];
r[i - 1][1] = y[i] - y[0];
r[i - 1][2] = z[i] - z[0];
}
if (r[0][0] * r[1][1] * r[2][2] + r[0][1] * r[1][2] * r[2][0] + r[1][0] * r[2][1] * r[0][2] - r[0][2] * r[1][1] * r[2][0] - r[0][1] * r[1][0] * r[2][2] - r[0][0] * r[1][2] * r[2][1] == 0)
printf("Yes\n");
else printf("No\n");
}
return 0;
}
前缀和,sum[i]=a[0]+a[1]+..+a[i]
b个就是sum[i]-sum[i-b]
然后遍历一下取最大的
也可以先加b个,然后后移一下,删第一个,加移动到的那个
#include
using namespace std;
int main() {
int n, a, b, score[100001], sum, temp;
scanf("%d", &n);
while (n--) {
scanf("%d%d", &a, &b);
score[0] = sum = 0;
for (int i = 1; i <= a; ++i) {
scanf("%d", &score[i]);
score[i] += score[i - 1];
}
for (int i = b; i <= a; ++i) {
temp = score[i] - score[i - b];
if (temp > sum)sum = temp;
}
printf("%d\n", sum);
}
return 0;
}
先把前后的#砍了
然后每个字母对应的数字转化出来,相同输出1,
不同把1砍了再比一次
#include
#include
using namespace std;
const string c[] = { "2","22","222","3","33","333","4","44","444","5","55","555","6","66","666","7","77","777","7777","8","88","888","9","99","999","9999" };
string change(string &s) {
string temp;
for (int i = 0; i < s.length(); ++i) {
if (s[i] >= 'a'&&s[i] <= 'z')s[i] = s[i] - 'a' + 'A';
if (s[i] == '#'&&temp[temp.length() - 1] == '1')continue;
if (s[i] == '#')temp += '1';
else temp += c[s[i] - 'A'];
}
return temp;
}
string change2(const string &s) {
string temp;
for (int i = 0; i < s.length(); ++i)
if (s[i] != '1')temp += s[i];
return temp;
}
int main() {
int n;
string a, b, c, d;
cin >> n;
while (n--) {
cin >> a >> b;
a = a.substr(a.find_first_not_of("#"));
a = a.substr(0, a.find_last_not_of("#") + 1);
b = b.substr(b.find_first_not_of("#"));
b = b.substr(0, b.find_last_not_of("#") + 1);
c = change(a);
d = change(b);
if (c == d)printf("1\n");
else printf("%d\n", change2(c) == change2(d) ? 2 : 3);
}
return 0;
}
gcd两个进化时间,然后按公共进化时间加,知道第一个大于第二个
#include
int gcd(int a, int b) {
int c = a % b;
while (c) {
a = b;
b = c;
c = a % b;
}
return b;
}
int main() {
int n, c1, d1, e1, c2, d2, e2, f2, day, cnt, base;
scanf("%d", &n);
while (n--) {
scanf("%d%d%d%d%d%d%d", &c1, &d1, &e1, &c2, &d2, &e2, &f2);
base = gcd(d1, d2);
day = 0;
while (c1 <= c2) {
day += base;
if (day%d1 == 0)c1 += e1;
if (day%d2 == 0) {
c2 += e2;
if (c2 > f2)c2 = f2;
}
}
printf("%d\n", day);
}
return 0;
}
注意一下用map存新来的星球之后就是裸的dijkstra(不懂的点这里dijkstra),但是比赛的时候忘记了。。。现推的= =
下面会给出两种写法,一种是pair的,一种是类的
注意如果pair用的不习惯的话,可以用下面的类的版本,可能比较好理解
#include
#include
#include
#include
类的版本
#include
#include
#include
#include
也是用map存新来的星球,然后裸的并查集(不会的点这 并查集),真的对不起寒假刷的并查集
#include
#include
#include
这题比赛的时候没敢想,但是仔细一想只是基础的博弈论
N局面先手必胜,P局面先手必败
无法移动的是P局面,能移动到P的是N局面,所有子局面是N局面的是P局面
2018.3.31是P局面,然后用dp往回推一下就好了
#include
#include
bool isLeap(const int &y) {
return y % 400 == 0 || y % 4 == 0 && y % 100 != 0;
}
int main() {
const int day[2][13] =
{ { 0,31,28,31,30,31,30,31,31,30,31,30,31 },
{ 0,31,29,31,30,31,30,31,31,30,31,30,31 } };
//0-118 +1900=1900-2018
bool win[120][13][32];
bool nextDay;
int n, y = 118, m = 3, d = 31, ty, tm;
memset(win, true, sizeof(win));
//无法移动的是P局面
win[y][m][d] = false;
do {
//缓存明天的状态
nextDay = win[y][m][d];
//今天的,也就是往前一天
--d;
if (d <= 0) {
--m;
if (m <= 0) {
--y;
m = 12;
}
d = day[isLeap(y + 1900)][m];
}
//下个月的
ty = y;
tm = m + 1;
if (tm == 13) {
tm = 1;
++ty;
}
//判断子局面是不是都是N局面
if (nextDay && win[ty][tm][d] && win[y + 1][m][d])win[y][m][d] = false;
} while (y || m != 1 || d != 1);
scanf("%d", &n);
while (n--) {
scanf("%d%d%d", &y, &m, &d);
printf("%s\n", win[y - 1900][m][d] ? "YES" : "NO");
}
return 0;
}
。。。模拟,大部分的数字是可以通过4个位置来确定的
#include
#include
int main() {
char map[5][10000];
memset(map, ' ', sizeof(map));
int len = 0, t;
for (int i = 0; i < 5; ++i) {
std::cin.getline(map[i], 9999);
t = strlen(map[i]);
if (t > len)len = t;
}
++len;
bool plus = true;
int pre = 0, now;
for (int i = 0; i < len;) {
if (map[0][i] == ' '&&map[1][i] == ' '&&map[2][i] == ' '&&map[3][i] == ' '&&map[4][i] == ' ')++i;
else if (map[2][i] == '*'&&map[2][i + 1] == '*'&&map[2][i + 2] == '*'&&map[2][i + 3] == ' ') {
plus = map[3][i + 1] == '*';
i += 3;
}
else if (map[0][i] == '*'&&map[1][i] == '*'&&map[2][i] == '*'&&map[3][i] == '*'&&map[4][i] == '*'&&map[0][i + 1] == ' ') {
now = 1;
++i;
if (plus)pre += now;
else pre -= now;
}
else {
char x = map[1][i], y = map[3][i], z = map[1][i + 4], r = map[3][i + 4];
if (x == '*'&&y == '*'&&z == '*'&&r == '*')now = map[2][i + 1] == '*' ? 8 : 0;
else if (x == ' '&&y == '*'&&z == '*'&&r == ' ')now = 2;
else if (x == ' '&&y == ' '&&z == '*'&&r == '*')now = map[2][i] == '*' ? 3 : 7;
else if (x == '*'&&y == ' '&&z == ' '&&r == ' ')now = 4;
else if (x == '*'&&y == ' '&&z == ' '&&r == '*')now = 5;
else if (x == '*'&&y == '*'&&z == ' '&&r == '*')now = 6;
else if (x == '*'&&y == ' '&&z == '*'&&r == '*')now = 9;
else {
++i;
continue;
}
i += 5;
if (plus)pre += now;
else pre -= now;
}
}
printf("%d", pre);
return 0;
}
给你们几个案例
***** ***** *****
* * * * * *
***** *** ***** *** *****
* * * * *
***** ***** *****
***** ***** *
* * * * * *
***** *** ***** *** *
* * * * *
***** ***** *
***** ***** *
* * * * *
***** *** ***** *** *
* * * * *
***** ***** *
* * ***** *
* * * * * *
***** *** ***** *** *
* * * * *
* ***** *
***** ***** *
* * * * *
***** *** ***** *** *
* * * * * *
***** ***** *
***** ***** *
* * * * *
* *** ***** *** *
* * * * *
* ***** *
***** ***** *
* * * * * *
***** *** ***** *** *
* * * * * *
***** ***** *
***** ***** *
* * * * * *
***** *** ***** *** *
* * * * *
***** ***** *
***** *****
* * * * *
*** ***** *** *****
* * * *
***** *****
***** ***** *
* * * * *
***** *** ***** *** *
* * * * *
***** ***** *
先判断是否共线,然后算空间直线的角度
#include
int main() {
int x[3], y[3], z[3], n, vec[3][4];
scanf("%d", &n);
while (n--) {
for (int i = 0; i < 3; ++i)scanf("%d%d%d", &x[i], &y[i], &z[i]);
vec[0][0] = x[1] - x[0]; vec[0][1] = y[1] - y[0]; vec[0][2] = z[1] - z[0];
vec[1][0] = x[2] - x[0]; vec[1][1] = y[2] - y[0]; vec[1][2] = z[2] - z[0];
vec[2][0] = x[2] - x[1]; vec[2][1] = y[2] - y[1]; vec[2][2] = z[2] - z[1];
vec[0][3] = vec[1][0] * vec[0][0] + vec[1][1] * vec[0][1] + vec[1][2] * vec[0][2];
vec[1][3] = -vec[2][0] * vec[0][0] - vec[2][1] * vec[0][1] - vec[2][2] * vec[0][2];
vec[2][3] = vec[2][0] * vec[1][0] + vec[2][1] * vec[1][1] + vec[2][2] * vec[1][2];
if (vec[1][1] * vec[0][0] == vec[1][0] * vec[0][1] && vec[0][1] * vec[1][2] == vec[1][1] * vec[0][2] && vec[0][0] * vec[1][2] == vec[1][0] * vec[0][2])printf("4\n");
else if (vec[0][3] < 0 || vec[1][3] < 0 || vec[2][3] < 0)printf("3\n");
else if (!vec[0][3] || !vec[1][3] || !vec[2][3])printf("1\n");
else printf("2\n");
}
return 0;
}