首页 > 其他分享 >AtCoder Beginner Contest 285

AtCoder Beginner Contest 285

时间:2023-01-16 00:55:23浏览次数:72  
标签:AtCoder Beginner ... int cin long 休息日 using 285

A - Edge Checker 2 (abc285 a)

题目大意

给定如下一棵树。

一棵树

给定 \(a,b(a<b)\),问两者是否有连边。

解题思路

观察数可发现其为二叉树,两者有连边当且仅当\(b=2a\)或 \(b=2a+1\)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int a, b;
    cin >> a >> b;
    if (a * 2 != b && a * 2 + 1 != b)
        cout << "No" << '\n';
    else 
        cout << "Yes" << '\n';

    return 0;
}



B - Longest Uncommon Prefix (abc285 b)

题目大意

给定一个长度为\(n\)字符串\(s\),对于每个\(i \in [1, n - 1]\) ,找到最大的\(l\)使得

  • \(i + l \leq N\)
  • \(\forall k \in [1, l], s_k \neq s_{k + i}\)

解题思路

数据范围不大,暴力即可。

即对于每个\(i\), 枚举 \(l\)从 \(1\)到第一个 \(s_l \neq s_{k+l}\)为止。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n;
    string s;
    cin >> n >> s;
    auto solve = [&](int x){
        int ans = 0;
        while(ans < n - x){
            if (s[ans] == s[ans + x])
                break;
            ++ ans;
        }
        return ans;
    };
    for(int i = 1; i < n; ++ i){
        cout << solve(i) << '\n';
    }

    return 0;
}



C - abc285_brutmhyhiizp (abc285 c)

题目大意

有一堆字符串,其字典序顺序为:

  • 'a', 'b', ..., 'z', 'aa', 'ab', ..., 'az', 'ba', 'bb', ..., 'bz', ..., 'za', 'zb', ..., 'zz', 'aaa', 'aab', ..., 'aaz', 'aba', 'abb', ..., 'abz', ..., 'zzz', 'aaaa', ...

现给定其中一个字符串,问其字典序大小。

解题思路

这题是abc171 c的反过来形式。

每个位置,以a-z的26为一循环,但第一次循环时还有一个0a可以看成是0a)。所以 a应当看成数字\(1\)。

因此高位转低位时,进位时\(26\),但末尾数字减去'A'后还要加一。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    string s;
    cin >> s;
    LL ans = 0;
    for(auto &i : s){
        ans = ans * 26 + (i - 'A' + 1);
    }
    cout << ans << '\n';

    return 0;
}



D - Change Usernames (abc285 d)

题目大意

给定\(n\)对字符串 \(s_i,t_i\)。表示有 \(n\)个人,原本叫 \(s_i\),现在需要改名为 \(t_i\)。

你现在要处理该请求,每次只能改一个人的名,问改名过程中会不会出现重名,即一个人改成\(t_i\)了,但还有另一个还没改名的 \(s_j = t_i\)

解题思路

字符串\(s_i\)改成 \(t_i\),则从 \(s_i\)连一条有向边到 \(t_i\)。

如果存在一个环,则改名过程必定重名。

有向边判环的方法即拓扑排序。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n;
    cin >> n;
    vector<string> s(n), t(n);
    set<string> qwq;
    map<string, int> tr;
    for(int i = 0; i < n; ++ i){
        cin >> s[i] >> t[i];
        qwq.insert(s[i]);
        qwq.insert(t[i]);
    }
    int cnt = 0;
    for(auto &i : qwq){
        tr[i] = cnt;
        ++ cnt;
    }
    vector<int> du(cnt);
    vector<vector<int>> edge(cnt);
    for(int i = 0; i < n; ++ i){
        int u = tr[s[i]];
        int v = tr[t[i]];
        edge[u].push_back(v);
        du[v] ++;
    }
    queue<int> team;
    for(int i = 0; i < cnt; ++ i){
        if (du[i] == 0)
            team.push(i);
    }
    while(!team.empty()){
        auto u = team.front();
        -- cnt;
        team.pop();
        for(auto &v : edge[u]){
            du[v] --;
            if (du[v] == 0)
                team.push(v);
        }
    }
    if (cnt)
        cout << "No" << '\n';
    else 
        cout << "Yes" << '\n';


    return 0;
}



E - Work or Rest (abc285 e)

题目大意

一周有\(n\)天。 给定一个长度为\(n\)的数组 \(a\)。

你需要指定 至少一天为休息日,其余为工作日。要求最大化工作日的产能。

一个工作日的产能定义为\(a_\min(x,y)\),其中 \(x\)是该日距离过去最近的休息日的天数, \(y\)是该日距离未来最近的休息日天数。注意周与周之间是连贯的,第一周的第一天的过去可以是上一周。

解题思路

如果不考虑连贯的影响,即认为一周是独立的,可以设\(dp[i]\)表示第 \(i\)天为休息日的情况下最大的产生值。转移时枚举上一次休息日的天数 \(j\)。

观察 \(j|j+1,j+2,...,i-1|i\),中间 \(j+1\)到 \(i-1\)的产能值,即为 \(a_1,a_2,...,a_2,a_1\),即下标是一个先递增后递减的规律,就是一个 \(a\)的前缀和的两倍,根据奇偶性可能多出一个\(a_i\)。这样转移可以 \(O(1)\)。复杂度就是 \(O(n^2)\)

但是一周并不是独立的,这样的方程具有后效性,归根结底就在于我们不知道一周第一次的休息日的日子,无法算出该日子之前和最后一个休息日之后的这几天的产能贡献。但如果设\(dp[i][j]\)表示第一次休息日在第 \(i\)天,然后在第 \(j\)天也是休息日的最大产能,其复杂度为 \(O(n^3)\)。

但是,注意到天与天之间没有区别的,意思就是说,如果我们确定了第一次休息日的天数\(a\),以及最后一次休息日的天数\(b\),那这两个休息日之间,里面休息日任意选,获得的产生最大值,其实就是 \(dp[b-a]\)。

因此我们预处理 \(dp[i]\),然后枚举第一次休息日\(a\)和最后一次休息日 \(b\)所在天数,那答案 \(dp[b-a]\)加上前 \(a\)天和后 \(b\)天工作日的产能贡献了。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n;
    cin >> n;
    vector<LL> a(n);
    for(auto &i : a)
        cin >> i;
    vector<LL> sum(n);
    partial_sum(a.begin(), a.end(), sum.begin());
    vector<LL> dp(n + 1, 0);
    auto solve = [&](int len){
        int dig = (len & 1);
        int half = (len >> 1);
        LL tmp = 0;
        if (half)
            tmp += 2ll * sum[half - 1];
        if (dig)
            tmp += a[half];
        return tmp;
    };
    for(int i = 1; i <= n; ++ i){
        for(int j = 0; j < i; ++ j){
            dp[i] = max(dp[i], dp[j] + solve(i - j - 1));
        }
    }
    LL ans = 0;
    for(int i = 0; i < n; ++ i)
        for(int j = i; j < n; ++ j){
            ans = max(ans, dp[j - i] + solve(i + n - j - 1));
        }
    cout << ans << '\n';


    return 0;
}



F - Substring of Sorted String (abc285 f)

题目大意

给定一个字符串\(s\),定义字符串 \(t\)为串 \(s\)各字母从小到大排序的字符串。进行 \(q\)次操作,操作分两种:

  • 1 x c,令 \(s_x = c\)
  • 2 x y,问\(s[x..y]\)是不是 串\(t\)的一个子串

解题思路

对于询问,其等价于:串\(a\)是串 \(t\)的子串,说明

  • 其串是递增的
  • 除首字母和末字母之外,中间的字母出现次数都是串 \(s\)中出现的次数

初步想法是预处理出\(l[i],r[i]\)数组表示第 \(i\)个字母的左边、右边第一个非该字母的位置。

对于一个询问 \(2\),\(s[r[x], l[y]]\)就是中间字母,其长度和各字母的出现次数都必须符合上述要求,也就是说这段字符串必须是确定的某一个,可以用字符串hash来判断,而由于操作一涉及到修改(该确定的字符串的hash可以在\(O(26)\)的复杂度计算出),因此需要用线段树hash的方式维护其hash值。

同时\(l[i],r[i]\)数组同样也要维护,考虑操作一的影响,这涉及到区间修改,需要用线段树维护,但逻辑稍微复杂,写起来比较麻烦。

神奇的代码



G - Tatami (abc285 g)

题目大意

给定一个\(h \times w\)的网格,格子上有 1 2 ?这三个符号,要求用\(1\times 1\)和 \(1\times 2\)(可旋转)的矩形覆盖。其中 1的格必须被 \(1\times 1\)的格子覆盖, 2的格必须被\(1 \times 2\)的格子覆盖, ?的则随意。

问是否存在一种方案。

解题思路

<++>

神奇的代码



Ex - Avoid Square Number (abc285 h)

题目大意

给定\(n\)和一个长度为 \(k\)的序列 \(E\),要求求一个长度为 \(n\)的正整数序列的数量,满足:

  • 所有元素都不是平方数
  • 所有元素的乘积为 \(\prod_{i=1}^{K}p_i^{E_i}\)

其中 \(p_i\)是第 \(i\)小的质数。

解题思路

<++>

神奇的代码



标签:AtCoder,Beginner,...,int,cin,long,休息日,using,285
From: https://www.cnblogs.com/Lanly/p/17054546.html

相关文章

  • ABC 285 ABCD
    https://atcoder.jp/contests/abc285/tasksA-EdgeChecker2题目大意:二叉树,给定两个数字,问其中一个是否和另一个数字直接连线?也即是是否是父节点?SampleInput1......
  • Atcoder Regular Contest ARC 153 A B C D 题解
    点我看题A-AABCDDEFE一个beautifulnumber是形如这样的:\(S1S1S3S4S5S5S7S8S7\)。如果选定了\(S1\),后面的数有100000种选法,所以先求出答案的\(S1\)。假设现在我们要求出......
  • Atcoder Regular Contest ARC 153 A B C D 题解
    点我看题A-AABCDDEFE一个beautifulnumber是形如这样的:\(S1S1S3S4S5S5S7S8S7\)。如果选定了\(S1\),后面的数有100000种选法,所以先求出答案的\(S1\)。假设现在我们要求出......
  • Atcoder Regular Contest ARC 153 A B C D 题解
    点我看题A-AABCDDEFE一个beautifulnumber是形如这样的:\(S1S1S3S4S5S5S7S8S7\)。如果选定了\(S1\),后面的数有100000种选法,所以先求出答案的\(S1\)。假设现在我们要求出......
  • AtCoder Beginner Contest 254(C,D,E,F)
    AtCoderBeginnerContest254(C,D,E,F)CC这个题是给你一个乱序的数组,你可以把ai和ai+k进行交换,我们需要判断是否可以最后变成从小到大的顺序那么我们可以想到所有下标对k......
  • AtCoder Regular Contest 153
    喜提全场独一无二的score!ATC还是很友善的,如果每题等分就寄了A签到B真的是凭着实力不会做的呀。。。太菜了发现两维可以分别做,所以考虑一维的情况,然而并不会对于两......
  • Atcoder abc275F
    Atcoderabc275F题意:给出一个长度为\(n\)的数组\(A=(a_1​,a_2​,…,a_N)\),问是否能通过删掉一些子段使剩下的数之和为\(q\)。若可以,求出最小操作次数,否则输出−1......
  • AtCoder Beginner Contest 282 G - Similar Permutation
    套路题题意求有多少个\(1\)到\(n\)的排列满足恰有\(k\)对在排列中相邻的数满足前小于后\(2\leqn\leq500,0\leqk\leq(n-1)\)思路f[i][j][k]表示已经......
  • AtCoder Beginner Contest 134
    AtCoderBeginnerContest134https://atcoder.jp/contests/abc134A-Dodecagon#include<bits/stdc++.h>usingnamespacestd;intmain(){inta;cin......
  • AtCoder Beginner Contest 042
    A-IrohaandHaiku(ABCEdition)#include<bits/stdc++.h>usingnamespacestd;int32_tmain(){inta=2,b=1;for(inti=1,x;i<=3;i++......