AtCoder Beginner Contest 285(D-G)

D - Change Usernames (atcoder.jp)

        (1)题目大意        

                每个用户都要改变自己的名称从A-B,但是他们不想自己改的名称被别人用掉了,因此让你判断是否可以改。

         (2)解题思路

                这种类似于匹配的问题,可以想到并查集,我们可以先hash每个名称,然后判断是否有两个名称出现在同一集合即可。

         (3)代码实现

#include "bits/stdc++.h"
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define ll long long
#define db double
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
unordered_map<string,int> mp;
int cnt;
struct UFS {
    int f[N],siz[N];
    void init(int n) {for(int i=1;i<=n;i++)siz[i]=1,f[i]=i;}
    int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
    bool same(int x,int y){return find(x)==find(y);}
    void merge(int x,int y) {if(!same(x,y))siz[find(y)]+=siz[find(x)],f[find(x)]=find(y);}
    int qsz(int x){return siz[find(x)];}
}comb;
int get(string s)
{
    if(!mp.count(s)) mp[s]=++cnt;
    return mp[s];
}
void solve()
{
    int n;
    cin>>n;
    comb.init(2*n);
    bool ok=true;
    rep(i,1,n) {
        string s1,s2;
        cin>>s1>>s2;
        int x=get(s1),y=get(s2);
        if(comb.same(x,y)) ok=false;
        else comb.merge(x,y); 
    }
    if(ok) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

E - Work or Rest (atcoder.jp)

        (1)题目大意

        现在有n天,若当天放假生产力则为0,否则为a[i],定义两个假期之间的生产效率为,其中n为距离\sum^{n}_{i=1}A[\frac{i+1}{2}]

         (2)解题思路

                我们考虑dp[i][j]表示当前是第i天,已经连续工作了j天的效率最大为多少。

                那么就有dp[i][j] = max(dp[i][j],dp[i-1][j-1])表示当前为工作日

                dp[i][0]=max(dp[i-1][j-1]+s[j-1],dp[i][0])表示当前为假期,前面已经有j-1天工作了的效率。

                注意最后一天为假期我们的dp值是没有更新的,因此我们取答案的时候要加上s[i]。

        (3)代码实现

#include "bits/stdc++.h"
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define ll long long
#define db double
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 5010;
ll s[N],dp[N][N],a[N];
void solve()
{
    int n;
    cin>>n;
    rep(i,1,n) cin>>a[i],s[i]=s[i-1]+(a[(i+1)>>1]);
    rep(i,1,n) rep(j,1,i) {
        dp[i][j]=max(dp[i-1][j-1],dp[i][j]);
        dp[i][0]=max(dp[i-1][j-1]+s[j-1],dp[i][0]);
    }
    ll ans=0;
    rep(i,1,n) ans=max(ans,dp[n][i]+s[i-1]);
    cout<<ans<<endl; 
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

F - Substring of Sorted String (atcoder.jp)

        (1)题目大意

                给你一个长度为N的串S,第一个操作是把第x个字符换成c,第二个操作是询问[l,r]这个串是否为原串排序后的子串。

         (2)解题思路

                考虑若[l,r]串若能成为原串排序后子串,有以下两个条件。

                        1.[l,r]的逆序对数量为0

                        2.[l,r]除了首尾字母的数量可以少于原串,中间的必须要和原串相同。

                我们可以想到第一个条件可以用逆序对的方式用树状数组处理出来。

                第二个条件我们也可以开26个树状数组统计。

        (3)代码实现

#include "bits/stdc++.h"
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define ll long long
#define db double
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl
#define no cout << "NO" << endl
#define lowbit(x) x&-x
using namespace std;
const int N = 2e5 + 10;
char s[N];
int seg[28][N],cnt[26],n;
void add(int p,int x,int v)
{
    while(x<=n) {
        seg[p][x] += v;
        x += lowbit(x);
    }
}
int qry(int p,int x)
{
    int res=0;
    while(x>=1) {
        res += seg[p][x];
        x -= lowbit(x);
    }
    return res;
}
void solve()
{
    scanf("%d%s",&n,s+1); 
    rep(i,1,n) {
        add(s[i]-'a',i,1);
        if(i>1&&s[i]<s[i-1]) add(27,i,1); 
    }
    int q;
    char ch;
    scanf("%d",&q);
    while(q--) {
        int op,l,r;
        scanf("%d",&op);
        if(op==1) {
            scanf("%d %c",&l,&ch);
            char vm = s[l];
            if(l>1&&s[l]<s[l-1]) add(27,l,-1);
            if(l<n&&s[l]>s[l+1]) add(27,l+1,-1);
            s[l] = ch;
            if(l>1&&s[l]<s[l-1]) add(27,l,1);
            if(l<n&&s[l]>s[l+1]) add(27,l+1,1);
            add(vm-'a',l,-1);add(s[l]-'a',l,1);
        }
        else {
            scanf("%d%d",&l,&r);
            if(qry(27,r)-qry(27,l)) puts("No");
            else {
                bool ok=true;
                rep(j,s[l]-'a'+1,s[r]-'a'-1) {
                    cnt[j]=qry(j,r)-qry(j,l-1);
                    if(cnt[j]!=qry(j,n)) {
                        ok=false;
                        break;
                    }
                }
                if(ok) puts("Yes");
                else puts("No");
            }
        }
    }
}
int main()
{
    int T = 1;
    while(T --) solve();
    return 0;
}

G - Tatami (atcoder.jp)

        (1)题目大意

                给你一个W*H的二维矩阵,对于每个1,必须有1个1*1的方块覆盖,每个2,必须由1*2或者2*1的方块覆盖,?可以被1*1或者1*2或者2*1的方块覆盖,问最后能否使这个矩阵被完全覆盖。

         (2)解题思路

                很容易想到1在这个矩阵没啥限制,因此不用管1,只需要管2和?的匹配,由于每一个2和?只能被使用一次,又是一个匹配问题,因此我们考虑最大流拆点。

### AtCoder ABC 中的拓扑排序解题思路 在处理图论问题时,拓扑排序是一种非常有用的工具,尤其适用于有向无环图(DAG)。对于 AtCoder Beginner Contest (ABC) 中涉及拓扑排序的问题,通常会围绕如何构建和遍历 DAG 展开。 #### 构建图结构 为了实现拓扑排序,首先需要建立一个合适的图表示方法。常见的做法是使用邻接表来存储节点之间的关系[^1]: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 7; vector<int> G[MAXN]; // 邻接表表示法 int indegree[MAXN]; // 记录每个顶点入度数 queue<int> q; // 存储当前入度为0的结点队列 ``` #### 初始化入度数组并加入起始点 通过读取输入数据更新各节点的入度情况,并将所有初始入度为零的节点放入队列中等待处理[^2]: ```cpp for(int i=1;i<=n;++i){ cin >> u >> v; G[u].push_back(v); ++indegree[v]; } // 将所有入度为0的节点压入队列 for(int i=1;i<=m;++i) if(!indegree[i]) q.push(i); ``` #### 进行广度优先搜索完成拓扑序排列 利用 BFS 来逐步移除已访问过的节点及其对应的边,直到无法继续为止。每次从队首取出一个元素作为当前被处理的对象,随后将其指向的所有其他节点的入度减一;如果某个时刻某节点变为新的起点,则立即将其加入到待处理列表里去[^3]: ```cpp while (!q.empty()) { int cur = q.front(); ans.push_back(cur); // 加入答案序列 q.pop(); for(auto &next : G[cur]){ --indegree[next]; if(indegree[next]==0) q.push(next); } } if(ans.size()!=m) cout << "存在环路"; else{ for(auto &node:ans) printf("%d ", node); } ``` 上述代码片段展示了完整的基于BFS算法框架下的拓扑排序过程,在实际比赛中可以根据具体题目调整细节部分以适应不同场景需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值