浙江工商大学2020年新生赛部分题解 (一)

站神的 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 0xa,0yb,0zc
请问有多少种满足条件的三元组 ( 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,c106

题解

好家伙,真正的签到题都在最后
其实这题看最开始的通过率就知道,它不是最简单的题
这时候应该转换策略,去读其他题

我看许多人提交的代码都是直接三个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=zx也就随之确定
但是注意到 x x x取到某些值时, y = z − x ∉ [ 0 , k 2 ] y=z-x \not∈[0, k2] y=zx[0,k2]
所以 y y y的范围还要缩小一些, 只有 x x x取太大,让 z − x ≤ 0 z-x\leq0 zx0才会有这样的情况发生
所以 y y y的最终范围是 [ m a x ( 0 , z − a ) , m i n ( z , b ) ] [max(0, z - a), min(z, b)] [max(0,za),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]上的点数
只有以下四种情况,分类讨论计算也行
p1

代码

#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 n104

题解

算是一个思维题(想到了就很简单)
因为对于最大数来说,和别的数一起算平均数永远会被"平均",也就是只会变小不会变大
那么我们直接输出最大值即可

其实你们看看样例猜一猜,因为都是输出数列中最大数

代码

#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;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值