站神的 A+B problem
题意
对于
0
≤
x
≤
a
,
0
≤
y
≤
b
,
0
≤
z
≤
c
0 \leq x \leq a, 0 \leq y \leq b, 0 \leq z \leq c
0≤x≤a,0≤y≤b,0≤z≤c
请问有多少种满足条件的三元组
(
x
,
y
,
z
)
(x, y, z)
(x,y,z),满足
x
+
y
=
z
x + y = z
x+y=z
a
,
b
,
c
≤
1
0
6
a,b,c \leq 10 ^ 6
a,b,c≤106
题解
好家伙,真正的签到题都在最后
其实这题看最开始的通过率就知道,它不是最简单的题
这时候应该转换策略,去读其他题
我看许多人提交的代码都是直接三个for暴力枚举
显然是不行的,这样复杂度是
O
(
n
3
)
O(n^3)
O(n3)
现在来看看正解
我们不能枚举
x
,
y
,
z
x,y,z
x,y,z三个参数,只需要枚举其中一个参数就能算出所有答案
这里为了方便,我们枚举
z
=
1
,
2
,
3
,
.
.
.
,
c
z=1,2,3,...,c
z=1,2,3,...,c
当我们确定
z
z
z的值时
x
x
x的范围也确定了,为
[
0
,
m
i
n
(
z
,
a
)
]
[0, min(z, a)]
[0,min(z,a)],不妨记为
[
0
,
k
1
]
[0, k1]
[0,k1],同理
y
y
y的范围就确定了,为
[
0
,
m
i
n
(
z
,
b
)
]
[0, min(z, b)]
[0,min(z,b)],不妨记为
[
0
,
k
2
]
[0, k2]
[0,k2]
x
+
y
=
z
x+y=z
x+y=z,
3
3
3个参数只要确定
2
2
2个,剩下的参数就固定了
即确定
x
=
0
,
1
,
2
,
.
.
.
,
k
1
x=0, 1, 2, ...,k1
x=0,1,2,...,k1,那么
y
=
z
−
x
y=z-x
y=z−x也就随之确定
但是注意到
x
x
x取到某些值时,
y
=
z
−
x
∉
[
0
,
k
2
]
y=z-x \not∈[0, k2]
y=z−x∈[0,k2]
所以
y
y
y的范围还要缩小一些, 只有
x
x
x取太大,让
z
−
x
≤
0
z-x\leq0
z−x≤0才会有这样的情况发生
所以
y
y
y的最终范围是
[
m
a
x
(
0
,
z
−
a
)
,
m
i
n
(
z
,
b
)
]
[max(0, z - a), min(z, b)]
[max(0,z−a),min(z,b)]
这样我们只需要
O
(
n
)
O(n)
O(n)即可计算全部答案
直观点当我们确定
z
z
z的值时
相当于在二维平面上画一条直线
x
+
y
=
z
x+y=z
x+y=z,计算落在
x
=
[
0
,
a
]
,
y
=
[
0
,
b
]
x=[0,a],y =[0,b]
x=[0,a],y=[0,b]上的点数
只有以下四种情况,分类讨论计算也行
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int main() {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
long long ans = 0, mn = min(a + b, c);
//注意z最多取到min(a+b, c), 否则会出现上面黄色情况, 即所有线都在范围外面
for (int z = 0; z <= mn; z++)
ans = ans + (min(z, b) - max(0, z - a) + 1);//确定的y的范围中
printf("%lld\n", ans);
return 0;
}
站神的演讲
题意
给你一个长度为
n
n
n的数列,求某区间的最大平均值
n
≤
1
0
4
n\leq10^4
n≤104
题解
算是一个思维题(想到了就很简单)
因为对于最大数来说,和别的数一起算平均数永远会被"平均",也就是只会变小不会变大
那么我们直接输出最大值即可
其实你们看看样例猜一猜,因为都是输出数列中最大数
代码
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int main() {
int n;
while (scanf("%d", &n) != EOF) {
int mx = -INF;
for (int i = 1; i <= n; i++) {
int x; scanf("%d", &x);
mx = max(mx, x);
}
printf("%d\n", mx);
}
return 0;
}
打破复读机
题意
判断字符串存不存在连续两个相同字母
题解
真·签到
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
char s[N];
int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%s", s + 1);
int n = strlen(s + 1), flag = 0;
for (int i = 2; i <= n; i++)
if (s[i] == s[i - 1]) flag = 1;
printf("%s\n", flag ? "Yes" : "No");
}
return 0;
}