Codeforces Round #656 (Div. 3) 部分题解(D、E、F)

[D. a-Good String](a-Good String)
思路:
很明显对于 ‘a’ ,有两种选择,在左区间和右区间。
分析一下 ‘a’。
如果’a’ 串 左区间全为 ‘a’ ,把其变为’a’ 的代价为 x ,那么右区间一定是 ‘b’ 串,把右区间变为’b’ 串的代价为 y(这里递归处理),其代价为 x+y。
如果’a’ 串 右区间全为 ‘a’ ,把其变为’a’ 的代价为 z ,那么左区间一定是 ‘b’ 串,把左区间变为’b’ 串的代价为 f(这里递归处理),其代价为 z+f。
最后每次取个min。

code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair<int,int>
#define pal pair<ll,ll>
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
char str[man];

int dfs(int rt,int l,int r){
   if(l==r)return str[l]!='a'+rt-1;
   int x = 0,y = 0,z = 0,f = 0;
   int m = l + r >> 1;
   for(int i = l;i <= m;++i){
       if(str[i]!='a'+rt-1)f++;
   }
   for(int i = m+1;i <= r;++i){
       if(str[i]!='a'+rt-1)z++;
   }
   x = dfs(rt+1,l,m);
   y = dfs(rt+1,m+1,r);
   return min(x+z,y+f);
}

signed main() {
   #ifndef ONLINE_JUDGE
       freopen("in.txt", "r", stdin);
       //freopen("out.txt","w",stdout);
   #endif
   int t;
   cin >>t;
   while(t--){
       int n;
       scanf("%d %s",&n,str+1);
       printf("%d\n",dfs(1,1,n));
   }
   return 0;
}

E. Directing Edges
拓扑排序。
如果其有向边已经组成了环,那么则无解。
否则可以通过改变无向边方向使其为有向无环图。

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

所以我们只需要处理有向的边,进行一次拓扑排序,在拓扑过程中,对于每个点出队列的顺序从小到大进行编号,编号小的点一定只能指向编号大的点。
所以存一下每条边,如果当前 u 的编号小于 v 的编号,则 u–> v 。否则 v–>u。
一定要满足编号小的指向编号大的。

code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair<int,int>
#define pal pair<ll,ll>
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
int du[man],u[man],v[man];
vector<int>sp[man];
int cnt[man],num = 0;
queue<int>q;
void top(){
    while(q.size()){
        int u = q.front();q.pop();
        cnt[u] = ++num;
        for(auto v:sp[u]){
            du[v]--;
            if(!du[v])q.push(v);
        }
    }
}

signed main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    int t;cin >>t;
    while(t--){
        int n,m;cin >> n >> m;
        num = 0;
        for(int i = 1;i <= n;++i){
            du[i] = cnt[i] = 0;
            sp[i].clear();
        }
        for(int i = 1;i <= m;++i){
            int o;scanf("%d%d%d",&o,&u[i],&v[i]);
            if(o){
                du[v[i]]++;
                sp[u[i]].pb(v[i]);
            }
        }
        for(int i = 1;i <= n;++i){
            if(!du[i])q.push(i);
        }
        top();
        if(num<n)printf("NO\n");
        else{
            printf("YES\n");
            for(int i = 1;i <= m;++i){
                if(cnt[u[i]]<cnt[v[i]])printf("%d %d\n",u[i],v[i]);
                else printf("%d %d\n",v[i],u[i]);
            }
        }
    }
    return 0;
}

F. Removing Leaves
也类似于拓扑排序的思想,先把叶子节点加入队列,然后维护每个节点的叶子节点个数sz和它的度du,
从队列取出队头u,标记 u 已访问过,用 u 去更新与他相连的顶点时(这个u一定是一个叶子节点),那么与他相连的且没有访问过的节点du–,sz++。当 sz 为 k 的倍数时,可以进行一次删除操作,答案加一。同时如果当前节点的 du 为一且 sz 为 k 的倍数,那么就丢入队列。
其大概过程就是边缘向中间走的过程。

code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair<int,int>
#define pal pair<ll,ll>
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
int du[man],vis[man],sz[man];
vector<int>sp[man];

signed main() {
    #ifndef ONLINE_JUDGE
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    int t;cin >> t;
    while(t--){
        int n,k;cin >> n >> k;
        for(int i = 1;i <= n;++i){
            du[i] = sz[i] = vis[i] = 0;
            sp[i].clear();
        }
        for(int i = 1;i < n;++i){
            int u,v;scanf("%d%d",&u,&v);
            du[u]++;du[v]++;
            sp[u].pb(v);
            sp[v].pb(u);
        }
        queue<int>q;
        ll ans = 0;
        for(int i = 1;i <= n;++i)if(du[i]==1){
            q.push(i);
            //vis[i] = 1;
        }
        while(q.size()){
            int u = q.front();q.pop();
            vis[u] = 1;
            for(auto v:sp[u]){
                if(vis[v])continue;
                du[v]--;
                sz[v]++;
                if(sz[v]%k==0){
                    ans++;
                }
                if(du[v]==1&&sz[v]%k==0){
                    q.push(v);
                   // vis[v] = 1;
                }
            }
        }
        cout <<ans <<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43571920/article/details/107428753
今日推荐