• Codeforces Round 895 (Div. 3)


    A. Two Vessels

    求出目标水位,然后计算倒水的次数向上取整即可

    1. void solve(){
    2. db a, b, c; cin >> a >> b >> c;
    3. print(int(ceil((max(a, b) - (abs(b + a) / 2)) / c)));
    4. }

    B. The Corridor or There and Back Again

    对于每个可能被激活的陷阱,计算该陷阱激活后可以走到的最右边的距离,答案就是所有最远距离里的最小值

    1. void solve(){
    2. int n; cin >> n;
    3. int ans = inf;
    4. while (n--){
    5. int a, b; cin >> a >> b;
    6. ans = min(ans, a + (b - 1) / 2);
    7. }
    8. print(ans);
    9. }

    trap是在刚进入时激活的,所以可以移动的步数是b - 1

    C. Non-coprime Split

    预处理sqrt(1e7)内的质数,然后对于每个l,r,去扫描一遍质数数组,对于每个质数做计算看是否存在符合条件的结果。

    1. vi primes;
    2. void PreProcess(){
    3. primes = sievePrimes(4444); //函数模板
    4. }
    5. void solve(){
    6. int l, r; cin >> l >> r;
    7. liter(prime, primes){
    8. int a = (l / prime - 1)* prime, b = (r / prime - 1) * prime;//如果除以Prime后不减1,可能会出现:l==r且l被prime整除,则prime + l > r。r%prime >= 0,但是没有 - 1,导致prime + b> r
    9. if (a > 1 && prime + a >= l && prime + 1 <= r){print(prime, a);return;}
    10. else if (b > 1 && prime + b >= l && prime + b<= r){print(prime, b); return;}
    11. }
    12. print(-1);
    13. }

    一开始读错题了,以为a,b都要在l,r区间内。

    第一种算法预处理了1e7的质数,TLE。

    第二种算法尝试用2与[l, r]之间的偶数进行匹配, WA。

    第三种算法对每个质数尝试找到一个解,AC。

    为什么在寻找含有prime的因子时一定要被prime除了以后将结果-1,而且这种方法一定正确?

    因为r/prime - 1>=1必须成立,才可能有解。如果这个式子不成立,说明r最多只能包含一个当前的prime,不可能包含第二个也含有prime的因子。比如r= 5, r/2-1 = 1,可以包含2,2。r = 3, r/2 -1 = 0,r范围内只能包含一个2,不可能包含第二个2出来。

    所以也可以这么理解,先将r降为当前prime最大整数倍r = r / prime * prime,然后看r中是否包含了至少2个prime,即r / prime >= 2。这两个条件都满足,则一定有解。

    至于为什么要计算L,因为做题时没有想到L的计算是非必须的。只要单独的把R拿出来进行计算,L最后只用来做大小的比较即可,代码也可以AC。

    如果按L来计算的话,应该是这样的:L = L / prime  + (L % prime != 0),然后再判断L是否小于R,L中是否包含了至少2个prime即可。

    D. Plus Minus Permutation

    统计x下标出现的次数,y下标出现的次数,以及两者同时出现的次数。

    贪心策略:将从n开始计数的大的数放到x的下标上,从1开始计数的小的数放到y的下标上,其他的数无所谓。因为位置最多只能有n个,所以这种放置策略一定正确。

    1. void solve(){
    2. ll n, x, y; cin >> n >> x >> y;
    3. ll x1 = n / x, y1 = n / y, z = n / lcm(x, y);//x和y的最小公倍数
    4. x1 -= z, y1 -= z;
    5. ll r = n, l = 1;
    6. ll a = (r - x1 + 1 + r) * (x1) / 2;
    7. ll b = (y1 + l) * y1 / 2;
    8. print(a - b);
    9. }

    一开始居然看成了把加减法看成了乘数法qaq
     

    E. Data Structures Fan

    给长度为n的字符串01序列和长度为n的数组,将数组按字符串中为0还是为1分成两部分。q个询问,每个询问可能是将区间LR中的数取反,或者询问数组中所有字符串对应位置为0或者为1的异或和。

    预处理一个前缀异或和,以及数组中1的异或和,数组中0的异或和。区间修改时将两个异或结果与区间异或和[L, R]做一次运算即可。

    1. void solve(){
    2. int n; cin >> n;
    3. vi a(n + 1); LITER(x, a) cin >> x;
    4. string s; cin >> s;
    5. s = ' ' + s;
    6. vi prefix(n + 1);
    7. int z = 0, o = 0;
    8. lfor (i, 1, n){
    9. prefix[i] = prefix[i - 1] ^ a[i];
    10. if (s[i] == '1'){o ^= a[i];}
    11. else z ^= a[i];
    12. }
    13. int q; cin >> q;
    14. vi ans;
    15. while (q--){
    16. int c; cin >> c;
    17. if (c == 2){
    18. int d; cin >> d;
    19. ans.pb(d == 0 ? z : o);
    20. }
    21. else{
    22. int l, r; cin >> l >> r;
    23. o ^= prefix[r] ^ prefix[l - 1];
    24. z ^= prefix[r] ^ prefix[l - 1];
    25. }
    26. }
    27. print(ans);
    28. }

    算法正确性的保证在于:区间取反说明区间中的0都变成了1,1 都变成了0。如果[L, R]中有新的数变成了1,那么1一定要跟他们做运算(增加这些数到结果中),如果有1变成了0,那么1也要跟他们做运算(从结果中消除这部分数),对于0同理。

    写完E题已经晚上11点半,洗洗睡了。等有机会FG再见

  • 相关阅读:
    【Java 基础篇】Java TCP通信详解
    Unable to load ‘@webpack-cli/serve‘ command问题解决
    Jest 学习笔记
    通过数组模拟理解队列、环形队列
    IBL(Image-Based Lighting)
    [NewStarCTF 2023] web题解
    CC3链分析与复现
    「分享学习」SpringCloudAlibaba高并发仿斗鱼直播平台实战完结
    ardupilot 中电机输出逻辑及电机转轴状态分析
    【数据治理】揭开主数据管理的陷阱
  • 原文地址:https://blog.csdn.net/m0_73965117/article/details/132759034