链接:https://ac.nowcoder.com/acm/contest/3007
题解:https://ac.nowcoder.com/discuss/367149
😭😭😭我tcl,这里只是记录做题思路和代码供个人回顾和参考。
- A 配对
- B 图
- C 汉诺塔
- D 重排列
- E 立方数
- F 十字阵列
- G 括号序列
- H 云
- I 导航系统
- J 签到题
A 配对
思路:
当时想的是把
A
A
A和
B
B
B的前
k
k
k大的数前后交叉着相加,因为感觉既然要最大化第
k
k
k大的和,那么第
k
k
k大之前的更大的不能很大,要把前
k
k
k大的数分的平均,这样才能最大化第
k
k
k大的和。感觉对了😀。上面给出的题解中有证明(使用调整法证明的,就简单几句话,不是很懂)。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, k;
int a[100005], b[100005], sum[100005];
bool cmp(int A, int B) { return A > B; }
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i<= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i<= n; i++) {
scanf("%d", &b[i]);
}
sort(a+1, a+n+1, cmp);
sort(b+1, b+n+1, cmp);
for (int i = 1, j = k; i <= k; i++, j--) {
sum[i] = a[i] + b[j];
}
sort(sum+1, sum+k+1, cmp);
printf("%d\n", sum[k]);
return 0;
}
D 重排列
思路:
排序后二分,容易看出
A
A
A,
B
B
B的顺序是无所谓的,要求满足条件
1
≤
i
≤
N
1≤i≤N
1≤i≤N,有
A
i
≤
B
i
A_i≤B_i
Ai≤Bi,数据范围
N
N
N是
1
0
5
10^5
105,
O
(
n
2
)
O(n^2)
O(n2)的复杂度肯定是不行的,所以考虑更小的复杂度。在把
A
A
A,
B
B
B从小到大排序后,我们可以想到,
A
A
A中的数如果能放在
B
B
B的第
i
i
i位上,那么它也能放在更往后的位置上,那么我们就可以根据这个来二分
A
A
A。遍历
B
B
B,求
A
A
A中小于等于
b
[
i
]
b[i]
b[i]的数的个数。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1e6+5;
int n;
ll a[maxn], b[maxn];
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%lld", &a[i]);
}
for (int i = 0; i < n; i++) {
scanf("%lld", &b[i]);
}
sort(a, a+n);
sort(b, b+n);
ll ans = 1;
for (int i = 0; i < n; i++) {
ll cnt = upper_bound(a, a+n, b[i]) - a - i;
ans = (ans % mod * cnt % mod) % mod;
}
printf("%lld\n", ans);
return 0;
}
E 立方数
思路:
赛后补题。数论的题,不看题解打死我也想不出😭😭😭。
唯一分解定理:
N
=
p
1
a
1
∗
p
2
a
2
∗
p
3
a
3
∗
.
.
.
.
.
.
∗
p
n
a
n
N=p_1^{a_1}*p_2^{a_2}*p_3^{a_3}*......*p_n^{a_n}
N=p1a1∗p2a2∗p3a3∗......∗pnan
from题解
考虑直接一些的做法,尝试对每个N作质因数分解,经简单的统计可得出答案,复杂度 O ( T ∗ N 1 / 2 ) O(T*N^{1/2}) O(T∗N1/2)。
我们先做简单一点的优化,容易发现其实只要枚举 1 0 6 10^6 106(也就是 N 1 / 3 N^{1/3} N1/3)以内的质数就好,复杂度 O ( T ∗ N 1 / 3 / ln ( N 1 / 3 ) ) O(T*N^{1/3}/\ln(N^{1/3})) O(T∗N1/3/ln(N1/3))。
再作进一步的分析,如果我们仅使用 N 1 / 4 N^{1/4} N1/4(记为W)以内的质数去试除,那么最后余下的数X仅具有大于W的因子,此时X要么是一个完全立方数,要么对答案没有任何贡献,只需要使用二分法来验证X是不是一个完全立方数即可,复杂度 O ( T ∗ N 1 / 4 / ln ( N 1 / 4 ) ) O(T*N^{1/4}/\ln(N^{1/4})) O(T∗N1/4/ln(N1/4))。
这篇博客有详细分析证明 https://blog.csdn.net/qq_21433411/article/details/104357188?tdsourcetag=s_pctim_aiomsg
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 31700; //31623
ll p[N], lf[N];
bool book[N];
int cnt;
void prime()
{
for (int i = 2; i < N; i++)
{
if (!book[i])
{
p[cnt] = i; //素数
lf[cnt++] = i * i * i; //素数的立方
}
for (int j = 0; j < cnt && i * p[j] < N; j++)
{
book[i * p[j]] = true;
if (i % p[j] == 0)
{
break;
}
}
}
}
int main()
{
prime();
int T;
scanf("%d", &T);
while (T--)
{
ll n, A = 1;
scanf("%lld", &n);
for (int i = 0; i < cnt && p[i] <= n; i++)
{
while (n % lf[i] == 0)
{
A *= p[i];
n /= lf[i];
}
while (n % p[i] == 0)
{
n /= p[i];
}
}
ll l = 1, r = 1000000;
while (l <= r)
{
ll mid = (l + r) >> 1;
if (mid * mid * mid < n)
{
l = mid + 1;
}
else
{
r = mid - 1;
}
}
if (l * l * l == n)
{
A *= l;
}
printf("%lld\n", A);
}
return 0;
}
F 十字阵列
思路:
只用一个二维数组的话在输入的时候复杂度会特别高 ❌
用
a
[
.
.
.
]
a[...]
a[...],
b
[
.
.
.
]
b[...]
b[...],
w
[
.
.
.
]
[
.
.
.
]
w[...][...]
w[...][...]分别记录行,列,和每个格子重复受到的伤害,计算结果时减掉
w
[
i
]
[
j
]
w[i][j]
w[i][j]就好了。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
int n, m, h;
ll a[2002], b[2002], w[2002][2002];
int main() {
scanf("%d%d%d", &n, &m, &h);
ll xi, yi, zi;
for (int i = 1; i <= h; i++) {
scanf("%lld%lld%lld", &xi, &yi, &zi);
a[xi] += zi;
b[yi] += zi;
w[xi][yi] += zi;
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
ans += (a[i] + b[j] - w[i][j]) * (i + j) * 1ll;
ans %= mod;
}
}
printf("%lld\n", ans);
return 0;
}
G 括号序列
思路:
经典的括号匹配问题,简化版,只有小括号。可以用栈做,也可以用两个变量记录左右括号的数量。
Code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
cin >> T;
while (T--)
{
int n;
string str;
cin >> n >> str;
int l = 0, r = 0, sum = 0, ans = 0;
for (int i = 0; i < n; i++)
{
if (str[i] == '(')
l++, sum++;
else if (sum > 0)
r++, sum--;
else
ans++;
}
cout << (ans + l - r) << endl;
}
return 0;
}
J 签到题
思路:
签到题。“No”的情况是不存在的,所以只要能构成三角形,就是“Yes”。不要先画三角形再推圆的半径,先画三个相切的圆再画出三角形,这样好想。
{
x
+
y
=
a
x
+
z
=
b
y
+
z
=
c
\begin {cases} x+y=a \\ x+z=b \\ y+z=c \end{cases}
⎩⎪⎨⎪⎧x+y=ax+z=by+z=c 已知
a
,
b
,
c
a,b,c
a,b,c 解三元一次方程。
Code:
#include <bits/stdc++.h>
using namespace std;
double a[3], b[3];
int main()
{
scanf("%lf%lf%lf", &a[0], &a[1], &a[2]);
sort(a, a + 3);
if (a[0] + a[1] <= a[2])
{
printf("wtnl\n");
}
else
{
printf("Yes\n");
b[0] = (a[0] + a[1] - a[2]) / 2;
b[1] = a[0] - b[0];
b[2] = a[2] - b[1];
printf("%.2lf %.2lf %.2lf\n", b[0], b[1], b[2]);
}
return 0;
}