久违的教育专场,担心hack担心了一天(无奈)
A题
题意大致是 Polycarp做了一个训练计划,给出训练的天数和每天的训练量,然后当累积训练量达到总训练量的一半或者以上的时候,Polycarp会在那一天庆祝,输出那一天是第几天。
坑点估计是总和sum/2的时候存在0.5的情况吧,这里笔者在求一半的时候先判断是不是奇数,如果是就 /2+1,不是就 /2。
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
using namespace std;
const int maxn = 2*(int)(1e5) + 1000;
const int inf = 0x3f3f3f3f;
const int mod = 2520;
const double eps = 1e-3;
typedef long long LL;
typedef unsigned long long ull;
int a[maxn];
int main() {
int n;
while (~scanf("%d", &n)) {
LL sum = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum += a[i];
}
LL ave = sum / 2;
if (sum & 1) ave += 1;
int ans;
LL cnt = 0;
for (int i = 1; i <= n; i++) {
cnt += a[i];
if (cnt >= ave) {
ans = i;
break;
}
}
printf("%d\n", ans);
}
return 0;
}
B题
给出一个座位的抽象字符串,.(点号)表示能坐,*表示不能坐。
现在有两个系的学生要坐座位,并且同一个系的学生不能坐在一起(也就是要隔着坐)。
问最多能坐多少个学生。
假设学生人数充足。
因为只能隔着座,当一段空着的座位是偶数个的时候,显然最大的坐法就是直接隔着坐直接填满。
如果是奇数的话,显然隔着坐一定有一个系的学生多出一个,根据贪心显然把这个位置给剩余学生多的系坐。
然后就是在上述情况时要判断学生数是否比可坐的座位数少了
(简单来说就是ifelse大法)
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
using namespace std;
const int maxn = 2*(int)(1e5) + 1000;
const int inf = 0x3f3f3f3f;
const int mod = 2520;
const double eps = 1e-3;
typedef long long LL;
typedef unsigned long long ull;
char str[maxn];
int main() {
int a, b;
int n;
while (~scanf("%d%d%d", &n, &a, &b)) {
scanf("%s", str);
str[n] = '*';
str[n + 1] = '\0';
n++;
int cnt = 0;
bool flag = true;
int ans = 0;
for (int i = 0; i <= n; i++) {
if (a == 0 && b == 0) break;
if (str[i] == '.') {
cnt++;
}
else if (str[i] == '*') {
if (cnt & 1) {
int tmp1 = cnt / 2 + 1, tmp2 = cnt / 2;
if (a > b) {
if (a - tmp1 >= 0) {
a = a - tmp1;
ans += tmp1;
}
else {
ans += a;
a = 0;
}
if (b - tmp2 >= 0) {
b = b - tmp2;
ans += tmp2;
}
else {
ans += b;
b = 0;
}
}
else {
if (a - tmp2 >= 0) {
a = a - tmp2;
ans += tmp2;
}
else {
ans += a;
a = 0;
}
if (b - tmp1 >= 0) {
b = b - tmp1;
ans += tmp1;
}
else {
ans += b;
b = 0;
}
}
}
else {
int tmp1 = cnt / 2;
if (a - tmp1 >= 0) {
a -= tmp1;
ans += tmp1;
}
else {
ans += a;
a = 0;
}
if (b - tmp1 >= 0) {
b -= tmp1;
ans += tmp1;
}
else {
ans += b;
b = 0;
}
}
cnt = 0;
}
}
printf("%d\n", ans);
}
return 0;
}
C题
给出一个串,问最少删除多少个数字能使得剩下的数字按顺序能组成一个平方数(无前导零)
读者一定要注意前导零(笔者虽然读题时注意到了,但是写的时候就忘了,然后就wa了一发)
然后因为数据量只有1e9也就是10位数,暴力dfs枚举肯定能过 。
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
using namespace std;
const int maxn = 2*(int)(1e5) + 1000;
const int inf = 0x3f3f3f3f;
const int mod = 2520;
const double eps = 1e-3;
typedef long long LL;
typedef unsigned long long ull;
char str[11];
int len, ans;
void dfs(int i, int del, int num) {
if (i == len) {
if (num == (int(sqrt(num)))*(int(sqrt(num)))&&num!=0) {
ans = min(ans, del);
}
return;
}
int tmp = num * 10 + str[i] - '0';
if (tmp == 0) dfs(i + 1, del + 1, tmp);
else dfs(i + 1, del, tmp);
dfs(i + 1, del + 1, num);
}
int main() {
while (~scanf("%s", str)) {
len=strlen(str);
ans = inf;
dfs(0, 0, 0);
//printf("%d\n", kk);
if (ans == inf) printf("-1\n");
else printf("%d\n", ans);
}
return 0;
}
D题
给出一串数字,现在有一种操作。
选择这串数字中的x,它在这串数字中的出现次数是>=2的,并且是同类数字中的最左边的。
现在把这样的x的最左边的拿出来,加在到第二次出现x的x上(也就是那个x*2),直到串中不存在相同的数字。(语死早)
还是看例子吧
样例
[3,4,1,2,2,1,1] → [3,4,2,2,2,1] → [3,4,4,2,1] → [3,8,2,1][3,4,1,2,2,1,1] → [3,4,2,2,2,1] → [3,4,4,2,1] → [3,8,2,1]
首先第一个出现次数>=2的数字是1,把最左边的1加到第二个1上,变成了2.以此类推
首先这道题在不断的合并过程中会产生原串中不存在的数字,也就是如果你用map的话实际开销并不是原串的个数,有可能更多。(笔者就是被坑在这里,比赛的时候re到怀疑人生)
这里首先观察这个操作的规律性,首先最后会出现哪些数字与位置无关,因为这个操作实际只与有多少个相同的数字有关。如果我们从数字最小的开始两两合并的话,最后一定能得到一个和最终结果数字相同,顺序不一定相同的串。
那么我们就可以考虑,先把最终结果算出来,然后再想办法把这个最终结果按照某些方法排序出结果。
然后就是如果弄出位置关系,显然因为操作中两个数合并之后会放在右边,那么只要建立一个结构体,每次合并的时候把右边的下表赋值给合并数就行了。
这里笔者用优先队列防止合并次数过多使得空间复杂度上升(估计会有 nlogn 的空间复杂度?)
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 2 * (int)(1e5) + 1000;
const int inf = 0x3f3f3f3f;
const int mod = 2520;
const double eps = 1e-3;
typedef long long LL;
typedef unsigned long long ull;
struct nodes {
LL val;
int index;
nodes() {}
nodes(LL u, int v) :val(u), index(v) {}
bool operator <(const nodes&a)const {
if (val == a.val) return index>a.index;
return val > a.val;
}
};
bool cmp(nodes a, nodes b) {
return a.index <b.index;
}
priority_queue<nodes>que;
vector<nodes>ans;
int main() {
int n;
while (~scanf("%d", &n)) {
while (!que.empty())
que.pop();
ans.clear();
LL x;
for (int i = 1; i <= n; i++) {
scanf("%I64d", &x);
que.push(nodes(x, i));
}
while (que.size() >= 2) {
nodes g = que.top();
que.pop();
nodes h = que.top();
if (g.val == h.val) {
que.pop();
que.push(nodes(g.val * 2, max(g.index, h.index)));
}
else
ans.push_back(nodes(g.val, g.index));
}
ans.push_back(nodes(que.top().val, que.top().index));
sort(ans.begin(), ans.end(), cmp);
int len = ans.size();
printf("%d\n", len);
for (int i = 0; i < len; i++) {
printf("%I64d", ans[i]);
printf("%s", i < len - 1 ? " " : "\n");
}
}
return 0;
}
其他的摸了