比赛链接:https://ac.nowcoder.com/acm/contest/3005
- A 欧几里得
- B 括号序列
- C 子段乘积
- D 子段异或
- E 最小表达式
- F 树上博弈
- G 音乐鉴赏
- H 坐火车
- I 匹配星星
- J 二维跑步
A 欧几里得
解题思路:
我是找规律看出来的,一直试试试,试出了前几项,很容易猜到是一个斐波那契数列🤡(别打我)
a:1 b:0 t:0
a:2 b:1 t:1
a:3 b:2 t:2
a:5 b:3 t:3
a:8 b:5 t:4
提前求出
f
i
b
o
n
a
c
c
i
fibonacci
fibonacci 数列就好了,注意前几项特判,数据爆int
,要开long long
。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100];
int main()
{
a[0] = 2;
a[1] = 3;
for (int i = 2; i <= 80; i++) a[i] = a[i - 1] + a[i - 2];
int T, n;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
if (n == 0)
printf("1\n");
else
printf("%lld\n", a[n]);
}
return 0;
}
B 括号序列
解题思路:
栈匹配括号的基础题。
遍历括号序列,遇到左括号进栈,遇到右括号匹配栈顶括号……
不是合法的括号序列:
- 右括号与栈顶不匹配
- 遇到右括号,栈为空
- 遍历完后栈不为空
Code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str;
cin >> str;
int len = str.length();
stack<char> s;
for (int i = 0; i < len; i++)
{
if (str[i] == '(' || str[i] == '[' || str[i] == '{')
{
s.push(str[i]);
}
else
{
if (s.empty())
{
cout << "No" << endl;
return 0;
}
if ((s.top() == '(' && str[i] == ')') || (s.top() == '[' && str[i] == ']') || (s.top() == '{' && str[i] == '}'))
{
s.pop();
}
else
{
cout << "No" << endl;
return 0;
}
}
}
if (s.empty())
cout << "Yes" << endl;
else
cout << "No" << endl;
return 0;
}
C 子段乘积
一开始想到的是用类似前缀和,求出了“前缀乘积”,然后
m
u
l
[
l
,
r
]
=
m
[
r
]
/
m
[
l
−
1
]
mul[l, r]=m[r]/m[l-1]
mul[l,r]=m[r]/m[l−1],这样涉及到乘法逆元,没关系,求乘积的时候顺便求出逆元就好了,然而还是不行,后来发现不能包含0,要按照所有的0分段,分别求每段的子段乘积取最大值,太麻烦了😖,所以又想到了线段树,把普通线段树的加操作改成乘就OK了,非常简单,build
+query
搞定。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int N = 200000 + 10;
ll mul[N << 2];
ll lazy[N << 2];
//改成乘法,取模
void push_up(int root) { mul[root] = mul[root << 1] * mul[root << 1 | 1] % mod; }
void buildTree(int l, int r, int root)
{
lazy[root] = 0;
if (l == r)
{
ll x;
scanf("%lld", &x);
mul[root] = x;
return;
}
int mid = (l + r) >> 1;
buildTree(l, mid, root << 1);
buildTree(mid + 1, r, root << 1 | 1);
push_up(root);
}
ll query(int L, int R, int l, int r, int root)
{
if (L <= l && r <= R)
return mul[root];
int mid = (l + r) >> 1;
ll ans = 1;
if (L <= mid)
ans = (ans * query(L, R, l, mid, root << 1)) % mod; //这里记得也要改成乘法,取模
if (mid < R)
ans = (ans * query(L, R, mid + 1, r, root << 1 | 1)) % mod; //乘法 取模
return ans;
}
int main()
{
int n, k;
scanf("%d%d", &n, &k);
buildTree(1, n, 1);
ll ans = -1;
for (int i = 1, j = k; j <= n; i++, j++)
ans = max(ans, query(i, j, 1, n, 1));
printf("%lld\n", ans);
return 0;
}
D 子段异或
解题思路:
这个题困扰了我很久,dalao同学说循环+map😫???后来才想明白。
异或的性质:
a
a
=
0
a^a=0
aa=0,也就是说一个数异或两次相当于没参与异或,这里敲重点。
这道题我们就可以这样做:用一个数t
记录前
i
i
i 个数的异或,如果map[t]
不为0,说明前面出现过异或和为t
的段(假设是前
j
j
j 个数的异或为t
),t
(前
i
i
i个数) 异或 t
(前
j
j
j个数) = 0,不就相当于前
j
j
j 个数没有参与异或,所以异或为0的段就是
[
j
+
1
,
r
]
[j+1,r]
[j+1,r]。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll, ll> m;
int main()
{
int n;
ll a;
scanf("%d", &n);
ll t = 0, cnt = 0;
m[0] = 1; //初始值,对应区间[1,i]异或和为0时加1
for (int i = 0; i < n; i++)
{
scanf("%lld", &a);
t = t ^ a;
cnt += m[t]; //如果map中没有t,返回0
m[t]++;
}
printf("%lld\n", cnt);
return 0;
}
E 最小表达式
本来以为需要写高精加,愣是没写出来,看了出题人的解法后,仿佛打开了通往新世界的大门🤩。
贪心。基本的思路是把大的数字放到权值小的位置,然后相加。然后做相加的时候就脑子短路了😑,想的是写出具体cnt个数,一个一个加。简单的方法是先把每一个权值位相加,再计算进位。因为每个权值位的cnt个数顺序无所谓。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 500000 + 10;
char str[N];
int arr[11];
int sum[N];
int main()
{
scanf("%s", str);
int len = strlen(str);
int cnt = 1; //加数的个数
for (int i = 0; i < len; i++)
{
if (str[i] == '+') //多一个加号就多一个加数
cnt++;
else
arr[str[i] - '0']++;
}
int j = 0, k = 0;
//贪心,大的数字放在权值小的位置,cnt个数的权值小的位都放完了再往权值高为放
for (int i = 9; i > 0; i--)
{
while (arr[i]) //数字i,的数量是arr[i]
{
sum[k] += i; //sum[]记每个权值(10^i)位的和,相当于把cnt个数的每一位先单独加起来,然后再计算进位
arr[i]--;
j = (j + 1) % cnt;
if (!j)
k++; //cnt个数的第k位都放上数了,再往高位放
}
}
for (int i = 0; i < N - 1; i++) //计算每一位的进位
{
sum[i + 1] += sum[i] / 10;
sum[i] %= 10;
}
for (j = N - 1; j >= 0 && sum[j] == 0; j--); //去前缀0
for (; j >= 0; j--)
printf("%d", sum[j]);
printf("\n");
return 0;
}
F 树上博弈
Code:
G 音乐鉴赏
Code:
H 坐火车
Code:
I 匹配星星
Code:
J 二维跑步
Code: