首页 > 其他分享 >AcWing周赛62-64 中比较有意思的小题题解

AcWing周赛62-64 中比较有意思的小题题解

时间:2022-08-14 18:36:50浏览次数:121  
标签:周赛 cnt cout int 题解 cin ++ 62 ans

AcWing周赛62-64(选讲)

感觉比较思维

4502. 集合操作

https://www.acwing.com/problem/content/4505/

根据题意,肯定要使得所取的最大值最大,平均值最小。又因为每次放进来的的数字都是递增的,所以最大值必然取的是最新放入的那个 \(x\), 接下来考虑平均值,要使平均值尽可能小的话,就要保证数是从小到大取的,然后我们输入的x恰好满足了不减的性质,所以只需要维护一个前缀和(记录之前输入的x),然后从头依次选取,直到找到最小的平均值。
平均值满足一条性质:先递减后递增(常识,可以多写几项找规律),所以一旦发现平均值变大了,那么代表已经找到了最优答案。
还有一个性质就是当前的平均数是连着往后找的,不会回退,因为满先减后增的性质,严谨的证明可以去看y总的视频

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 5e5 + 5;
int m, cnt = 1, sum[N];

signed main () {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin >> m;
    int i = 1;
    while (m --) {
        int x, op;
        cin >> op;
        if (op == 1) {
            cin >> x;
            sum[cnt] = sum[cnt-1] + x;
            ++ cnt;
        }

        else {
            double ans = x;
            //int x = sum[cnt] - sum[cnt-1];

            for (; i < cnt; i ++) {
                //cout << "sum=" << sum[i] << endl;
                double aver = 1.0 * (sum[i] + x) / (i + 1);
                //经化简,只需比较x_{k+1}与上一个aver
                //cout << "aver=" << aver << endl;
                if (aver > ans)     break;
                ans = min (aver, ans);
            }
            i--;
            cout << fixed << setprecision(6) << x - ans << endl;
        }
    }
}

//后缀和优化

4501. 收集卡牌

https://www.acwing.com/problem/content/4504/

很简单的小题,但是一开始脑子没转过来,如果是第一次出现,就计入 \(cnt\),集齐了就一次性 \(erase\)

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
int n, m, a[N];

int main () {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin >> n >> m;
    int cnt = 0;
    while (m --) {
        int x;
        cin >> x;
        if (a[x] == 0)    cnt ++;
        a[x] ++;

        if (cnt == n) {
            cout << 1;
            for (int i = 1; i <= n; i ++) {
                a[i] --;
                if (a[i] == 0)  cnt --;
            }
        }
        else    cout << 0;
    }
}

4504. 字符串消除

https://www.acwing.com/problem/content/4507/

很难不让人想到上场多校的F - Candies

#include <bits/stdc++.h>

using namespace std;

int main () {
    string s;
    cin >> s;
    int n = s.size(), cnt = 0;
    stack <char> q;
    for (int i = 0; i < n; i ++) {
        if (q.empty())  q.push (s[i]);
        else {
            if (s[i] == q.top ()) {
                q.pop(), cnt ++;
            }
            else    q.push (s[i]);
        }
    }
    if (cnt & 1)    cout << "Yes\n";
    else    cout << "No\n";
}

4505. 最大子集

https://www.acwing.com/problem/content/4508/

不懂数学,感觉十分的困难

(懒得打公式,就丑丑的手写)

IMG_20220814_161028_edit_18865330585093.jpg

所以只需枚举数和公差即可。
要注意 \(multiset\) 比手写的 \(hash\) 慢,所以还是乖乖手写把

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 5,  M = 1999997, INF = 0x3f3f3f3f;
int n, h[M], a[N];
multiset <int> s;
vector <int> ans, tmp;

int find(int x) {
    int t = (x % M + M) % M;
    while (h[t] != INF && h[t] != x)
        if ( ++ t == M)
            t = 0;
    return t;
}

void print () {
    cout << "tmp: ";
    for (auto i : tmp)  cout << i << ' ';cout << endl;
    cout << "ans: ";
    for (auto i : ans)  cout << i << ' ';cout << endl;
}

int main () {
    scanf ("%d", &n);
    for (int i = 0; i < n; i ++)    scanf ("%d", &a[i]);
    sort (a, a + n);
    memset(h, 0x3f, sizeof h);


    //for (auto i : s)    cout << i << ' ';cout << endl;
    
    int cnt = 0;
    for (int i = 0; i < n; i++)  {//枚举数
        for (int j = 0; j <= 30; j++) { //枚举公差
            int d = (1 << j);
            tmp.push_back (a[i]);
            for (int k = 1; k <= 2; k++) { //看看与i相差2^j,2^{j+1}的数是否都存在
                int x = a[i] - d * k;
                //cout << "x=" << x << endl;
                if (h[find(x)] == INF)    break;
                tmp.push_back(x);
            }

            //看看放够没
            int sz = tmp.size();
            //print();
            if (cnt < sz) {
                cnt = sz;
                ans.clear();
                for (auto k : tmp)  ans.push_back (k);
                if (cnt == 3)   break; //找到答案了
            }
            tmp.clear();
            //print();
        }
        if (cnt == 3)   break; //找到答案了
        h[find(a[i])] = a[i];
    }

    cout << cnt << endl;
    //int x = ans[0], y = ans[1], z = ans[2];
    
    for (auto i : ans)  cout << i << ' ';

}

//找到一个该集合的最大子集,
//要求子集内的元素满足任意两元素之差的绝对值都是 2 的整数幂。

这题都整了老半天...

4507. 子数组异或和

https://www.acwing.com/problem/content/4510/

有意思的一道小题
主要是要考虑到异或与加法存在某种相似的关系,然后同理利用前缀和的性质来做

分析:
异或与加法有类似性质,所以可以直接使用前缀和
左半边 \(\bigoplus\) 右半边 \(= 0\)
\([i,j]\) 满足条件即 \(s_j\bigoplus s_{i-1}=0 -> s_j=s_{i-1}\)
hash统计出现过的次数
因为长度是偶数,所以下标分奇偶讨论

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 3e5 + 5;
int n, a[N], ans, sum;
unordered_map <int, int> h[2]; //

signed main () {
    cin >> n;
    for (int i = 1; i <= n; i ++)   cin >> a[i];
    h[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        sum ^= a[i]; //前缀异或和
        ans += h[i & 1][sum];
        h[i & 1][sum] ++;
    }
    
    cout << ans << endl;
}

//异或与加法有类似性质,所以可以直接使用前缀和
//左半边 ^ 右半边 = 0
//[i,j]满足条件即s[j]^s[i-1]=0 -> s[j]=s[i-1]
//hash统计出现过的次数
//因为长度是偶数,所以分奇偶讨论

4508. 移动的点

https://www.acwing.com/problem/content/4511/

因为是匀速,所以 \(a,b\) 能相遇的充要条件是 \(a,b\) 的速度向量为同一方向,且不是相对静止(就算 \(a\) 在 \(b\) 的后面,速度比他小也能相遇,因为时间是 \(-\infty\) 到 \(\infty\))

那么判断速度向量相等就只需要满足:

\[\frac{v_{y_j}-v_{y_i}}{v_{x_j}-v_{x_i}}=a \]

斜率相等
转化一下就变为

\[v_{y_j}-av_{x_j}=v_{y_i}-av_{x_i} \]

判断不是相对静止可以拿个 \(hash\) 表来存,同理,判斜率相等亦然

#include <bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> pii;
map<pii, int> V; //相对速度
map<int,int> W; //wi,速度方向
int ans;

signed main () {
    int n, a, b;
    cin >> n >> a >> b;
    for (int i = 1; i <= n; i++) {
        int x, vx, vy;
        cin >> x >> vx >> vy;
        int w = a * vx - vy;
        ans += W[w] - V[{vx, vy}];
        W[w] ++, V[{vx, vy}] ++;
    }
    cout << ans * 2; //ab相遇算两次
}


//相遇必须满足:(v_{yj} - v_{yi})/(v_{xj} - v_{xi})=a
//即a*v_{xj} - v_{yj} = a*v_{xi} - v_{yi}且相对速度不为0

标签:周赛,cnt,cout,int,题解,cin,++,62,ans
From: https://www.cnblogs.com/CTing/p/16585910.html

相关文章

  • [POI2006]Pro-Professor Szu & ZLOJ 练习62 B
    writtenon2022-08-09题目不难,但是需要总结一下。题意很明确,就不过多阐述了。读完题目后,很明显可以建反图,然后就会有两种方法。第一种方法是直接拓扑排序找环,这种方式......
  • P8245 [COCI2013-2014#3] PAROVI & ZLOJ 练习62 D
    writtenon2022-08-09一道有趣的计数题。首先题面中最引人注目的就是两个整数的数据范围。很显然,暴力的思路,枚举所有数,找出每一位上每一种数字的个数这种方法是不可行......
  • Acwing 第 64 场周赛 C 4507. 子数组异或和(异或+前缀和)
    https://www.acwing.com/problem/content/4510/给定一个长度为n的整数数组a1,a2,…,an。请你统计一共有多少个数组a的非空连续子数组能够同时满足以下所有条件:该......
  • T265119 拯救公主--题解
    题目描述公主索菲亚被关在一个有大小一样的方格构成的四四方方的迷宫里面,索菲亚就站在其中一个方格子上,拯救方案是这样的:要用一些地砖把公主所在的方格子之外的格子都铺上......
  • 1062 最简分数——20分
    一个分数一般写成两个整数相除的形式:N/M,其中M不为0。最简分数是指分子和分母没有公约数的分数表示形式。现给定两个不相等的正分数N1/M1和N2/M2,要求你按从小到大的顺序......
  • CF1712题解(E,F)
    E题意是让你求满足\(lcm(i,j,k)\geqi+j+k\)的三元组个数。我们通常都有一个直观感觉,lcm应该是各数之积级别的,换句话说,不满足\(lcm(i,j,k)\geqi+j+k\)的三元组个数......
  • LeetCode Pow(x, n)算法题解 All In One
    LeetCodePow(x,n)算法题解AllInOnejs/ts实现Pow(x,n)50.Pow(x,n)https://leetcode.cn/problems/powx-n/https://www.youtube.com/watch?v=ZTACajQOb2Er......
  • 2022“杭电杯”中国大学生算法设计超级联赛(8) 题解
    A.Theramore考虑只对长度为3的子串进行操作,发现偶数位置的字符不会出现在奇数位置,奇数位置的字符不会出现在偶数位置。对奇偶位置字符进行排序即可。#include<bits/std......
  • 表达式 题解
    零、写在前面\(\texttt{洛谷の题目链接}\)与\(\texttt{Topsの题目链接}\)以及\(\texttt{Hydroの题目链接}\)这道题是\(\texttt{CSP-2020}\)普及组的第三题,但个......
  • 【题解】做题记录(2022.8)
    (之前的就暂时不补了就从以后的开始记)8.12CF1606CBanknotes题目分析:显然第\(i\)种货币可以用来组成\(a_{i+1}-a_{i}\)位,为了使得\(k\)最小,显然从低到高位依次......