比赛情况

我太菜了

  • A题 加减乘除不会

  • B题 二元一次方程不会

  • C题 gcd不会

  • 就会一个D题二分答案大水题,本来想比赛最后一分钟来一个绝杀,结果 Wrong Answer on test 4

比赛总结

  • 问题1:有点读不懂题目。

解决方法:读题目后如果发现没有看懂,再多读几遍样例,看看样例的解释,大概就懂了。(如果再读不懂就得锻炼自己的阅读理解了)

  • 问题2:花了点时间想了个假题。

解决方法:其实就是没有看懂题目,和问题1一样的方法去解决。

  • 问题3:卡在一个题动不了。导致后面会做的题没去做。

解决方法:因为有些知识点确实不太擅长,比如我在C题想了20min假题,又想了30min真题(雾,总觉得没有做出C就做D有些丢脸似的,其实大可以在C想不出的情况下看看D,万一D会做呢?如果不会D,就说明自己的水平有限了呗qwq

所以赶紧补题啊!

A

这题的意思我读了将近15min,,

给你n组询问,每次给你两个数a,b,问你把b分成a个数,使这a个数的平方和最小。

贪心:尽量选 b/a 左右的数,具体是选 (b%a)个(b/a+1),(a-(b%a))个(b/a)

Talk is cheap. Show me the code.

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
int n;
signed main()
{
    int n = read();
    while(n--) {
        int c = read(), sum = read();
        int x = sum/c, y = sum%c;
        printf("%lld\n",(x*x)*(c-y)+((x+1)*(x+1))*y);
    }
    return 0;
}

B

考虑现在已经是最终状态了,也就是 => 0 0

现在推回最初状态。

我们把两个数分别写成 2A+B , 2C+D

那他们的最终状态就是 2(0)+(0) , 2(0)+(0)

我们假设做一次[逆]运算1, 他们就会变成 => 2(0)+(0+x),2(0+x)+(0)

我们假设再做一次[逆]运算2(设这里为y),他们就会变成 => 2(0+y)+(0+x) , 2(0+x)+(0+y)

这里我们发现 A = D, B = C ,于是这两个数就可写成 a=2A+B, b=2B+A

二元一次方程,会解吧。

判断一下这个解A,B是否都为正整数就好了?

Talk is cheap. Show me the code.

#include<bits/stdc++.h>
using namespace std;
inline int read() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
int main()
{
    int T = read();
    while(T--) {
        int a = read(), b = read();
        int A =  (2*a-b)%3, B = (2*b-a)%3;
        if(A==0 && B==0 && (2*a-b)>=0 && (2*b-a)>=0) puts("YES");
        else puts("NO");
    }
    return 0;
}

C

裴蜀定理?

D

二分答案,看得出吧?

我是看了别人的代码才懂的。 二分一个最小的能力值,可以通过这个关卡。最后看一下有多少人的能力值大于这能力值。然后就是二分check这里,先把陷阱按L从小到大排好序。枚举每个陷阱。记录现在人最远的距离mx,如果这个陷阱没有被取消并且能力值过不去,mx可以先走到 L-1 这里来(并且是带着队伍走)这里只计算单次的时间(如果mx>L-1,当然就不这么走,相当于队伍还在后面,mx已经在前面了),然后mx走到R,这里计算3次的时间,去->回->去,相当于现在在mx,之后走到mxR,mx->(自己)mxR->(自己)mx->mxR(带队 )

Talk is cheap. Show me the code.

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
inline int read() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 2e5+7;
int m,n,K,t;
int a[N];
struct Node {
    int L,R,d;
    bool operator < (const Node &el) const {
        return L < el.L;
    }
}trap[N];
inline bool check(int c) {
    int tim = n+1, mx = 0;
    for(int i=1;i<=K;++i) {
        if(trap[i].d<=c || trap[i].R<=mx) continue;
        mx = max(mx, trap[i].L-1);
        tim += (trap[i].R-mx)*2;
        mx = trap[i].R;
    }
    return tim <= t;
}
int main()
{
    m = read(), n = read(), K = read(), t = read();
    for(int i=1;i<=m;++i) a[i] = read();
    for(int i=1,L,R,d;i<=K;++i) {
        L = read(), R = read(), d = read();
        trap[i] = (Node)<%L,R,d%>;
    }
    sort(trap+1, trap+1+K);
    int l = 0, r = N, mid, ans = INF;    //二分出最小的能力值,能力值越小,可以去的人就越多
    while(l <= r) {
        mid = (l+r)>>1;
        if(check(mid)) {
            ans = mid;
            r = mid - 1;
        } else l = mid + 1;
    }
    int sum = 0;
    for(int i=1;i<=m;++i)
        if(a[i] >= ans) ++sum;
    printf("%d\n",sum);
    return 0;
}