2021/1/23黑龙江农垦科技职业学院喜迎寒假多校联赛2(快乐ak场)题解
传送门:黑龙江农垦科技职业学院喜迎寒假多校联赛2(快乐ak场)
白天去老姐家撸狗勾了,没打,回家补的
进入比赛先看了眼榜,发现A题A的人最少,那我偏偏就从A题顺着往下做嘿嘿嘿(然后piapia打脸)
A 数组截取
注意!!本题只得了90!!原因是超时,并没有AC!!
有一段数组n 从中截取和为k的一部分 最长可以截取多长?(如果截取不到正好为k的情况下输出-1)
注意:
出题人:出个数组截取吧;验题人:数据太弱了加强一下;出题人:陷入沉思,OK
本题因为验题人吐槽,数据太弱所以加强了一点点,一点点.......
因为数据比较多 请使用你认为最快的读取方式 最省内存的运算方法。反正C++标程 500ms 256mb 内跑过去了。
输入描述:
第一行输入两个整数 n,k
1<n<=2×107
0<=k<=1018
第二行输入n个正整数(包含0)
a1 a2 .....an (0<=ai<=1012) 1<=i<=n
输出描述:
输出运算结果
输入
10 3
3 3 1 1 1 0 0 0 3 3
输出
6
拿到题,没什么特殊的思路,就是从头开始加,大了就减掉最前面的,然后记录长度更新最大值就好了
一开始用了个队列储存,后来想了想发现没有必要,就改成了一个head指向数列里的第一个数,然而最后还是没AC
快速读入快速输出都用了,还用了inline玄学加速,最后还手动O2都没用,做了半个小时,草,毁灭吧不做了
贴上90分代码,指不定哪天良心发现就想开了
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#pragma GCC optimize(2)
#define ll long long
using namespace std;
const int maxn = 2e7 + 1;
ll n, k, a[maxn], sum, cnt = 1, ans = -1;
inline ll read() {
ll x = 0, k = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') k = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * k;
}
inline void printt(ll x) {
if (x < 0) {
putchar('-');
x = -x;
}
if(x > 9) printt(x / 10);
putchar(x % 10 + '0');
}
int main() {
n = read(); k = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) {
sum += a[i];
while (sum > k) {
sum -= a[cnt];
cnt++;
}
if (sum == k)
ans = max(ans, i - cnt + 1);
}
printt(ans);
return 0;
}
B 群友们在排列数字
题目描述
群友们在玩一个游戏,共n个人在玩 每个人要在0-(n-1)中选一个数,注意每个数只能选择一次,
然后按照先后选择顺序拼成一个数,计算组成的数字是否可以整除k,
群友们想知道,如果选择方案不重复,最多有多少种情况可以整除k?
如果不可能整除k请输出-1;
输入描述:
第一行输入两个正整数 n,k
1<=n<=10,1<=k<=107
输出描述:
输出结果
输入
2 1
输出
2
一个dfs,直接暴力每一种情况看看能不能整除就可以
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define ll long long
using namespace std;
const int maxn = 11;
ll n, k, ans, vis[maxn];
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
inline void printt(ll x) {
if (x < 0) {
putchar('-');
x = -x;
}
if(x > 9) printt(x / 10);
putchar(x % 10 + '0');
}
inline void dfs(ll num, ll now) {
if (num == n) {
if (now % k == 0) ans++;
return;
}
for (int i = 0; i < n; i++) {
if (vis[i] == 0) {
vis[i] = 1;
dfs(num + 1, now * 10 + i);
vis[i] = 0;
}
}
}
int main() {
n = read(); k = read();
dfs(0, 0);
if (ans == 0) printf("-1");
else printt(ans);
return 0;
}
C gg查成绩
题目描述
这一天gg拿到了一份,超多的考试数据a 。
老师要求他按照询问数据告诉老师,第几个到第几个同学的分数和是多少 ?
gg最近入职字节跳动了,没有时间处理这种极其简单的问题,所以请你顺手秒一下。
输入描述:
第一行n m ( n个同学 m次询问)
1<=n<=106
1<=m<=104
第二行输入n个整数表示成绩
a1 a2 .....an (0<=ai<=100) 1<=i<=n
以下m行为两个整数bi bj 表示第几个到第几个同学(从1开始)
1<=bi<=bj<=n
输出描述:
m行查询结果
输入
10 3
11 22 33 44 55 66 77 88 99 10
1 4
2 10
5 7
输出
110
494
198
读完题:啊哈!线段树~(dbq最近在做线段树的题,看见查询区间和条件反射想到线段树...)
交完评分提交tag的时候才发现用前缀和就能做...下面放上我的线段树...真是小题大做了啊
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define ll long long
using namespace std;
const int maxn = 4e6 + 10;
ll n, m, a[maxn], x, y, ans;
struct node {
ll l, r, sum;
}tree[maxn];
inline void build(ll i, ll l, ll r) {
tree[i].l = l; tree[i].r = r;
if (l == r) {
tree[i].sum = a[l];
return;
}
ll mid = (l + r) >> 1;
build(i * 2, l, mid);
build(i * 2 + 1, mid + 1, r);
tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
}
inline ll search(ll i, ll l, ll r){
if (tree[i].l >= l && tree[i].r <= r)
return tree[i].sum;
if (tree[i].r < l || tree[i].l > r) return 0;
ll sum=0;
if (tree[i * 2].r >= l) sum += search(i * 2, l, r);
if (tree[i * 2 + 1].l <= r) sum += search(i * 2 + 1, l, r);
return sum;
}
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
int main() {
n = read(); m = read();
for (int i = 1; i <= n; i++) a[i] = read();
build(1, 1, n);
for (int i = 1; i <= m; i++) {
x = read(); y = read();
ans = search(1, x, y);
printf("%lld\n", ans);
}
return 0;
}
D issue与lifehappy给学生分组
题目描述
issue与lifehappy在给学生分组 现在他们手里有一组n分学生量化好的数据a 这份数据是一个数字,代表学生的大致实力
他们要给学生分成m组并且要求总实力和的最大值最小(ccpc抢名额战略,分散一点)
不过学生们已经拉帮结派的排好队了 所以 issue与lifehappy只能选取这组数据中的连续队列。
输入描述:
第一行 n m n个学生 分成m组
1<=m<=n<=106
第二行为n正整数an
a1 a2 .....an (0<=ai<=1011) 1<=i<=n(保证最终结果在ull内)
输出描述:
输出分组后总实力最大值的最小
输入
5 3
1 8 9 4 2
输出
9
二分答案,枚举可能的数值然后判断
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define ll long long
#define ull unsigned long long
using namespace std;
const int maxn = 1e6 + 10;
ll n, m, a[maxn];
ull l, r, mid;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
inline bool work(ull x) {
ull sum = 0;
ll cnt = 1;
for (int i = 1; i <= n; i++) {
sum += a[i];
if (sum > x) {
sum = a[i];
cnt++;
}
if (cnt > m) return false;
}
return true;
}
int main() {
n = read(); m = read();
for (int i = 1; i <= n; i++) {
a[i] = read();
r += a[i];
l = l > a[i] ? l : a[i];
}
while (l < r) {
mid = (l + r) >> 1;
if (work(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
E 删删删越小越好
题目描述
这一天Kadia与Majiagou在教学弟,
突然提出了一个问题 给你一个超大的数字 让你从中删掉几位 怎么让他最小?
这种签到题不会还有人写不出来吧 不会吧不会吧
输入描述:
第一行输入一个整数N
1<=len(N)<=2×107
第二行输入一个整数k代表删除几个数字
0<=k<=len(N)
输出描述:
输出结果
输入
10000
1
输出
0
说明
删掉1结果为0
输入
12347897187194164979
10
输出
1114164979
之前讲过这种题,我当时傻乎乎地先删大的数,于是就听取WA声一片
这题的正解是从前往后删,保留最小的数,然后比它大的就全删掉,直到不能删了为止
例如:1234441119111中删8个就会删掉23444、9然后再删1
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define ll long long
using namespace std;
const int maxn = 2e7 + 1;
int k, head;
char a[maxn];
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
int main() {
scanf("%s", a + 1); k = read();
int len = strlen(a + 1);
for (int i = 1; i <= len; i++) {
while (k > 0 && head >= 1 && a[head] > a[i]) {
head--;
k--;
}
a[++head] = a[i];
}
int now = 1;
while (a[now] == '0' && now < head) now++;
while (k > 0) {
head--;
k--;
}
for (int i = now; i <= head; i++) printf("%c", a[i]);
return 0;
}
F happy的异或运算
题目描述
我们都知道有一种位运算叫做异或,那么这道题是一道思维题。
给出一个整数n,请求出1-n之间选取两个数进行异或最大能得出多大?(两个数可以相同)
输入描述:
1 ≤ N ≤1018
输出描述:
无
输入
10000
输出
16383
输入
648
输出
1023
输入
324
输出
511
这是一道...结论题,只需让n对应的二进制的每一位都是1,就可以得到答案
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <queue>
#define ll long long
using namespace std;
ll n, ans;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
int main() {
n = read();
while (n) {
ans = ans << 1 | 1;
n >>= 1;
}
printf("%lld\n", ans);
return 0;
}
G Alan%%%
题目描述
又是欢快的一天,牛客多校算法训练营4又在日常%Alan。qcjj想知道到底Alan被%了多少次,所以整理了一下聊天记录。
如果一句话中存在Alan,那么那句话中的%都算%了Alan。由于可能话中有空格,所以去掉空格后形成的Alan也算Alan。
输入描述:
第一行输入整数n表示聊天记录行数
1<=n<=1000
以下n行每行一个字符串s代表聊天记录
1<=s.length<=1000
输出描述:
输出%Alan次数
输入
5
%alan%%
%Alan%%%
cdqwsq%% A l a n%%
%AC lan%%
%Alan%%%
输出
12
简单的模拟,没什么好说的
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <algorithm>
#include <queue>
#include <vector>
#define ll long long
using namespace std;
int n, ans;
string s;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) {
getline(cin, s);
int cnt = 0, flag = 0;
int len = s.size();
for (int i = 0; i < len; i++) {
if (s[i] == '%') cnt++;
if (s[i] == ' ') continue;
if (s[i] == 'A') flag = 1;
else if (flag == 1) {
if (s[i] == 'l') flag = 2;
else {
flag = 0;
break;
}
}
else if (flag == 2) {
if (s[i] == 'a') flag = 3;
else {
flag = 0;
break;
}
}
else if (flag == 3) {
if (s[i] == 'n') flag = 4;
else {
flag = 0;
break;
}
}
}
if (flag == 4) ans += cnt;
}
printf("%d\n", ans);
return 0;
}
H cg写项目
题目描述
这一天cg写了一个卡迪亚酒店客户端,客户端的数据是一张由用户名s,密码m,性别x,电话h组成的表,他想以用户的用户名为基准进行一下排序,短的在前,同样长度按照字典序小的在前,同用户名先输入的在前面。但是曹哥太忙了所以找你帮忙写一下数据处理。
输入描述:
n分数据
1<=n<=100
以下n行 为 s m x h
1<= s.length <=20
1<= m.length <=20
1<= x.length <=20
1<= h.length <=20
输出描述:
根据用户名排序规则排序后输出
输入
5
td1336065617 1336065617 n 13766949653
1336065617 1336065617 nc 137
ad1336065617 1336065617 na 111
03360651778 1 9 8
1 1 1 1
输出
1 1 1 1
1336065617 1336065617 nc 137
03360651778 1 9 8
ad1336065617 1336065617 na 111
td1336065617 1336065617 n 13766949653
用结构体sort一下就过了,唯一需要注意的就是排序方式,一开始看错了wa了一发QwQ
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#define ll long long
using namespace std;
int n;
struct node{
string name, pasw, sex, tel, len, num;
}a[110];
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
inline bool cmp(node x, node y) {
if (x.len != y.len) return x.len < y.len;
else if (x.name != y.name) return x.name < y.name;
return x.num < y.num;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) {
cin >> a[i].name >> a[i].pasw >> a[i].sex >> a[i].tel;
a[i].len = a[i].name.size();
a[i].num = i;
}
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++)
cout << a[i].name << " " << a[i].pasw << " " << a[i].sex << " " << a[i].tel << endl;
return 0;
}
I cg写项目加强版
和上题一样的,改一下大小就可以了
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#define ll long long
using namespace std;
int n;
struct node{
string name, pasw, sex, tel, len;
int num;
}a[1000010];
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
inline bool cmp(node x, node y) {
if (x.len != y.len) return x.len < y.len;
else if (x.name != y.name) return x.name < y.name;
return x.num < y.num;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) {
cin >> a[i].name >> a[i].pasw >> a[i].sex >> a[i].tel;
a[i].len = a[i].name.size();
a[i].num = i;
}
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++)
cout << a[i].name << " " << a[i].pasw << " " << a[i].sex << " " << a[i].tel << endl;
return 0;
}
J 比赛开始了清楚姐姐喊了一句:签到了签到了
题目描述
比赛开始了清楚姐姐喊了一句:签到了签到了 选手们纷纷开始签到,现在给出n个数字代表选手们签到所用秒数 请给出第几个选手最先签到。同秒数先输入的算快。
(不会吧 不会吧 不会有人用牛客不知道清楚姐姐吧)
输入描述:
第一行输入一个整数n
1<=n<=10000
第二行输入n个整数s
0<=s<=1000
输出描述:
一个数
输入
5
5 3 2 4 1
输出
5
签到题
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#define ll long long
#define INF 0x7fffffff
#pragma GCC optimize(2)
using namespace std;
int x, y = INF, n, ans;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> x;
if (x < y) {
y = x;
ans = i;
}
}
printf("%d", ans);
return 0;
}
完结撒花~
不早了,洗洗睡了