首页 > 其他分享 >AtCoder Beginner Contest(abc) 328

AtCoder Beginner Contest(abc) 328

时间:2023-11-15 12:23:12浏览次数:34  
标签:AtCoder abc idx int dfs long 328 节点 define




B - 11/11

难度: ⭐

题目大意

在某个世界一年有n个月, 每个月有di天, 问有多少个日期, 该日期和月份组成的数字都是一样的; eg: 11月的1日, 22月的22日;

解题思路

暴力就行;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=2e5+10;
int n,m;
int f[N];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        int x,y;
        cin>>x;
        if(i<10) y=i;
        else{
            if(i%10==i/10) y=i%10;
            else continue;
        }
        if(x>=y*10+y) m+=2;
        else if(x>=y) m++;
    }
    cout<<m;
    return 0;
}




C - Consecutive

难度: ⭐⭐

题目大意

给定一个字符串和m个询问, 每个询问都是一个区间, 问区间中有多少个连续两个相同字母的情况, "sss"看作2个;

解题思路

用前缀和来做就行, 注意边界问题;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=3e5+10;
int n,m;
int f[N];
signed main(){
    cin>>n>>m;
    string s;
    cin>>s;
    s=' '+s;
    for(int i=1;i<=n;i++){
        if(s[i]==s[i+1]){
            f[i]=f[i-1]+1;
        }
        else f[i]=f[i-1];
    }
    while(m--){
        int l,r;
        cin>>l>>r;
        cout<<f[r-1]-f[l-1]<<endl;
    }
    return 0;
}




D - Take ABC

难度: ⭐⭐⭐

题目大意

给定一个字符串, 从前往后遍历, 如果遇到连续的"ABC"就可以清除这三个字母, 注意在清除后新生成的也算; 输出操作后的字符串;

解题思路

跟括号匹配一个思想, 我们用一个堆才存放字母, 如果当前字母是'C', 并且堆中前两个是'A'和'B', 那么就可以把他们删掉; 所以只需要判定'C'即可;

神秘代码

#include<bits/stdc++.h>
//#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
#define endl '\n'
using namespace std;
const int N = 5e5 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m, idx;
char f[N];
signed main(){
    string s;
    cin>>s;
    s=' '+s;
    for(int i=1;i<s.size();i++){
        if(s[i]=='C'){
            if(idx>=2&&f[idx-1]=='A'&&f[idx]=='B') idx-=2;
            else f[++idx]='C';
        }
        else f[++idx]=s[i];
    }
    for(int i=1;i<=idx;i++) cout<<f[i];
    return 0;
}




E - Modulo MST

难度: ⭐⭐⭐

题目大意

给定n个点和m条边以及边的权值, 问这个图取模后的最小生成树的边权和是多少;

解题思路

因为本题是问取模后的最小值, 所以不能用之前学过的算法; 因为数据范围很小, 所以可以考虑暴力枚举, 暴力枚举时我们可以借鉴prim的思想, 我们把结点1作为生成树的根节点, 然后我们dfs节点2~n, 对于每个节点, 我们从所有与它相连的节点中挑选一个作为它的父节点; dfs完第n个节点后我们就得检查一下当前得到的生成树是否合法, 需要检查两个点, 一是每个节点都可以到达根节点, 二是没有环; 第一点可以根据dfs中得到的父子关系进行寻找, 第二点只需要在寻找的时候打个标记即可;
在ac后我突然想到以上的过程可以用并查集来优化, 我们只需要把kruskal算法暴力一下, 我们还是从节点1开始dfs, 然后通过并查集把所有节点连到一起, 这样到最后就不需要检查了, 因为并查集会自动避免非法情况, 但是使用并查集会有一个隐藏的坑, 就是关于dfs的回溯问题, 因为大部分并查集的板子会修改在find函数中修改中间节点的父节点来压缩路径, 但是这样回溯时还需要一一修改, 所以我们可以修改为不压缩路径即可;
而且中间还有一个插曲, 我发现在dfs中p[find(u)] = find(i)改成p[u] = find(i)也可以ac, 在模拟后发现我的这种写法是从下往上去建立并查集的链, 所以每次dfs中u都是某条链中最靠上的节点(也就是这条链的祖宗节点), 所以这两种写法是一致的;

神秘代码

//朴素
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
#define endl '\n'
using namespace std;
const int N = 100 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m, idx, k;
int res = 1e17;
int p[N];
bool st[N][N];
int f[N][N];
bool check(){
    for(int i=2;i<=n;i++){
        int x=i;
        map<int,int> mp;
        mp[i]=1;
        while(1){
            if(!p[x]){
                if(x!=1) return false;
                break;
            }
            x=p[x];
            if(mp[x]) return false;
            mp[x]=1;
        }
    }
    return true;
}
void dfs(int u,int sum){
    if(u>n){
        if(check())res=min(res,sum);
        return;
    }
    for(int i=1;i<=n;i++){
        if(st[u][i]){
            p[u]=i;
            dfs(u+1,(sum+f[u][i])%k);
        }
    }
}
signed main() {
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        f[a][b] = f[b][a] = c;
        st[a][b] = st[b][a] = true;
    }
    dfs(2,0);
    cout<<res;
    return 0;
}

//并查集
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
#define endl '\n'
using namespace std;
const int N = 100 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m, idx, k;
int res = 1e17;
int p[N];
bool st[110][110];
int f[110][110];
int find(int u){
    if(p[u] != u) return find(p[u]);
    else return p[u];
}
void dfs(int u,int sum){
    if(u==n){
        res=min(res,sum%k);
        return;
    }
    for(int i=1;i<=n;i++){
        int a=find(u), b=find(i);
        if(st[u][i]&&a!=b){
            p[a]=b;
            dfs(u+1,sum+f[u][i]);
            p[a]=a;
        }
    }
}
signed main() {
    cin >> n >> m >> k;
    for(int i=1;i<=n;i++) p[i]=i;
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        f[a][b] = f[b][a] = c;
        st[a][b] = st[b][a] = true;
    }
    dfs(1,0);
    cout<<res;
    return 0;
}




F - Good Set Query

难度: ⭐⭐⭐⭐

题目大意

解题思路

需要用到带权并查集...晚上补

神秘代码


标签:AtCoder,abc,idx,int,dfs,long,328,节点,define
From: https://www.cnblogs.com/mostimali/p/17833548.html

相关文章

  • AtCoder Beginner Contest 325
    A-Takahashisan#include<bits/stdc++.h>usingnamespacestd;#definelllonglongusingvi=vector<int>;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);strings,t;cin>>s>>t;cout<......
  • AT_abc230_f [ABC230F] Predilection 题解
    prelogue各位在比赛的时候一定要坚信自己的式子,然后去考虑自己的实现是不是挂了。本人在今天模拟赛的时候质疑自己的式子然后不看实现100->0。analysis考虑对这个给定数组进行前缀和,然后就将问题转化成为了求这个前缀和数组的子序列的个数。对于求子序列,我们很轻松可以写出......
  • [题解]AT_abc328_f [ABC328F] Good Set Query
    思路带权并查集模板。如果对于一个三元组\((a,b,c)\)如果它能够添加到\(S\)中一定满足如下条件中的一条:\(X_a,X_b\)满足其中有一个是「不确定」的。在这里\(X_i\)「不确定」指\(X_i\)没有与其它的任意\(X_j\)有关系。\(X_a,X_b\)有间接或直接的关系,但是能计算......
  • Toyota Programming Contest 2023#7(AtCoder Beginner Contest 328)
    ToyotaProgrammingContest2023#7(AtCoderBeginnerContest328)A.NotTooHard题意:将给定的数列\(a\)中数值小于\(x\)的数累加。解题思路:模拟。代码:#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;voidsolve(){ intn,x; cin>>n>>x;......
  • ABC328F题解
    原题链接洛谷题面提交记录闲话赛场就做了这道和A,喜提\(625\)大分。带权并查集练手题,有点像银河英雄传说。题目大意存在一个长度为\(N\)的数列\(X\),给定\(Q\)个三元组\((a_i,b_i,d_i)\),定义一个好集合为集合\(S\subseteq\{1,2,\dots,Q\}\),使得所有\(x\inS\)满......
  • ABC 328 题解
    A直接模拟即可。cin>>n>>m;for(inti=1;i<=n;++i){ intx;cin>>x; if(x<=m)sum+=x;}cout<<sum;B直接模拟即可。intn,ans;boolchk(intx,inty){ intdig=x%10;x/=10; while(x){ if(x%10!=dig)return0; x/=10; } while(y){ if(y%10......
  • ABC328F 题解
    blog。提供一个普通并查集+启发式合并做法。考虑直接维护\(X_i\)。对于\(X_u-X_v=w\),分四种情况。\(X_u,X_v\)都没被维护过。直接钦定\(X_u\getsw,X_v\gets0\),以后再改。\(X_u\)没被维护过,\(X_v\)被维护过。显然\(X_u\getsX_v+w\)。\(X_v\)没被维护过,\(X_u\)被......
  • ABC328G 题解
    blog。剩下几分钟的时候胡出来了,但是时间不够,痛失AK/dk。\(N\le22\),显然状压DP。\(dp_s\)表示确定\(s\)集合的元素所需的代价(这些元素都放在最前面)。确定了\(s\)后,发现会有\(\operatorname{popcount}(s)\)个元素堆在前面,那么枚举\([L,R]\)接在后面,也就是\([\opera......
  • AtCoder Beginner Contest 328
    A-NotTooHard(abc328A)题目大意给定\(n\)个数字和一个数\(x\)。问不大于\(x\)的数的和。解题思路按找要求累计符合条件的数的和即可。神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=longlong;intmain(void){ios::sync_with_stdi......
  • AtCoder Beginner Contest 328
    A傻逼题。B傻逼题C傻逼题D不难发现,每次添加一个字符,如果可以当前的答案组成ABC就删。然后模拟即可。E两种方法。二进制枚举使用了哪些边。可以发现有用的状态只有\(\binom{m}{n-1}\),上限大概\(10^5\),剩余无用状态过了就行。复杂度\(O(m2^m)\),但是跑的特别不满。......