Codeforces Round 954 (Div. 3) (A~F)(不会数学)

A - X Axis 

        

暴力枚举一下所有可能

void solve() 
{
	int a , b , c;
	cin >> a >> b >> c;
	int ans = 100;
	for(int i = 0 ; i <= 10 ; i ++){
		ans = min(ans , abs(i - a) + abs(i - b) + abs(i - c));
	}	
	cout << ans << endl;
}    

B - Matrix Stabilization 

        

可以观察到:若一个数比周围四个数都大,那么最终会变成四个数当中最大的哪一个。

        

void solve() 
{
	int n , m;
	cin >> n >> m;
	int mp[n][m];
	for(int i = 0 ; i < n ; i ++){
		for(int j = 0 ; j < m ; j ++){
			cin >> mp[i][j];
		}
	}	
	for(int i = 0 ; i < n ; i ++){
		for(int j = 0 ; j < m ; j ++){
			int ma = -1;
			if(i > 0){
				ma = max(ma , mp[i - 1][j]);
			}
			if(i + 1 < n){
				ma = max(ma ,  mp[i + 1][j]);
			}
			if(j > 0){
				ma = max(ma , mp[i][j - 1]);
			}
			if(j + 1 < m){
				ma = max(ma , mp[i][j + 1]);
			}
			cout << min(mp[i][j] , ma) << " ";
		}
		cout << endl;
	}
}   

C - Update Queries 

        

对字符串c以及ind数组进行排序,通过贪心可以知道,我们需要按照索引从小到大的修改字符串,同时一个位置只会有一个字母与之对应,因此只需要同时按照字符串c从小到大修改即可。

        

void solve() 
{
	int n , m;
	cin >> n >> m;
	string s;
	cin >> s;	
	int a[m];
	map<int,int>mp;
	for(int i = 0 ; i < m ; i ++){
		cin >> a[i];
		mp[a[i]]++;
	}
	char c[m];
	string str;
	cin >> str;
	for(int i = 0 ; i < m ; i ++){
		c[i] = str[i];
	}
	sort(c , c + m);
	int id = 0;
	for(auto it : mp){
		int x = it.first;
		x--;
		s[x] = c[id++];
	}
	for(int i = 0 ; i < n ; i ++){
		cout << s[i];
	}
	cout << endl;
}   

D - Mathematical 问题 

        

      归纳题,观察后可以发现:一定有一个两位数,因此我们可以枚举这个两位数,然后取最小值。

        接下来考虑如何取最小值:若存在数字0,那么可以通过都用乘法来将最终结果变成0,此外,若存在数字1,可以通过乘法将1消掉。除此之外的数,都是加法更加小。按照此策略来模拟即可。

        

void solve() 
{
	int n;
	cin >> n;
	string s;
	cin >> s;
	int mask[n];
	for(int i = 0 ; i < n ; i ++){
		mask[i] = s[i] - '0';
	}	
	int ans = 101010;
	for(int i = 1 ; i < n ; i ++){
		vector<int>tmp;
		int tot = 0;
		for(int j = 0 ; j < n ; j ++){
			if(j == i - 1){
				int x = mask[j] * 10 + mask[j + 1];
				tmp.pb(x);
				j++;
			}
			else{
				tmp.pb(mask[j]);
			}
		}
		for(auto it : tmp){
			if(it == 0){
				cout << 0 << endl;
				return;
			}
			if(it == 1){
				continue;
			}
			else{
				tot += it;
			}
		}
		if(tot == 0) tot++;
		ans = min(ans , tot);
	}
	cout << ans << endl;
}  

E - Beautiful Array 

        

        思路:我们对所有模k情况下相同的数放到一组,组内的任意两个数都可以通过操作变成相同的数。然后考虑一个组内怎么样才能使得答案最小,显然将相近的两个数放到两边可以将答案变小。因此只需要排序,然后对相邻的两个数两两配对即可。由于需要两两配对,因此若一个组内的数的个数为奇数,除非将一个数放在正中间,否则一定无法满足题意。

        若n为奇数,那么需要有一个数放在正中间,也就是需要有一个组内的数的个数为奇数。接下来考虑怎么计算将谁放在中间最合适。假设组内数的个数为n,那么需要找出k = n/2组数来进行配对,考虑将某个位置上的数放到中间后的答案是怎样的:从开头两两配对所组成的x组 + 从结尾两两配对所组成的y = k - x(0\leq x \leq k)。因此可以通过一个前缀数组跟一个后缀数组来记录这些值,然后遍历x来找到最小值。

        

void solve() 
{
	int n , k;
	cin >> n >> k;
	vector<int>idx[n];
	map<int,int>mp;
	int id = 0;
	set<int>st;		
	for(int i = 0 ; i < n ; i ++){
		cin >> a[i];
		int res = a[i] % k;
		if(st.count(res)){
			int idk = mp[res];
			idx[idk].pb(a[i] / k);
		}
		else{
			st.insert(res);
			mp[res] = id++;
			idx[mp[res]].pb(a[i] / k);
		}
	}
	int ans = 0;
	int f = 0;
	if(n & 1){
		f++;
	}
	for(int i = 0 ; i < id ; i ++){
		sort(idx[i].begin() , idx[i].end());
		if(idx[i].size() % 2 == 0){
			for(int j = 0 ; j < idx[i].size() ; j += 2){
				ans += idx[i][j + 1] - idx[i][j];
			}
		}
		else{
			if(f){
				int k = idx[i].size() / 2;
				vector<int>pre(k + 5  , 0);//总共k个值
				int id = 1;
				for(int j = 0 ; j + 1 < idx[i].size() ; j += 2){
					pre[j / 2 + 1] = pre[j / 2] + idx[i][j + 1] - idx[i][j];
				}				
				vector<int>suf(k + 5 , 0);
				for(int j = idx[i].size() - 1 ; j >= 1 ; j -= 2){
					suf[j / 2 - 1] = suf[j / 2 ] + idx[i][j] - idx[i][j - 1];
				}
				int ma = 1e18;
				for(int j = 0 ; j <= k ; j ++){
					ma = min(ma , pre[j] + suf[j]);
				}
				ans += ma;
				f--;
			}
			else{
				f = -1;
				break;
			}
		}
	}
	if(!f){
		cout << ans << endl;
	}
	else{
		cout << -1 << endl;
	}
}   

 F - Non-academic 问题

        

        可以发现:若存在一个多元环(环上的点大于2),那么无法通过删除一条边来改变他们的连通情况。因此,对于那些多元环而言,我们可以将其缩成一个点。最终:我们通过缩点可以得到一个没有环的连通图,也就是树。接下来只需要通过枚举树上的每条边,将其变成两棵树,然后求出答案的最小值即可。

        用无向图的tarjan可以将这些多元环缩成一个点,然后再用树的算法来统计子树的大小跟答案即可。(无向图的tarjan跟有向图的tarjan很像,只需要一条边不连续走两次即可)

        

        

// Problem: F. Non-academic Problem
// Contest: Codeforces - Codeforces Round 954 (Div. 3)
// URL: https://codeforces.com/contest/1986/problem/F
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
#define int long long
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
	return b > 0 ? gcd(b , a % b) : a;
}

LL lcm(LL a , LL b){
	return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
	for(int i = 0 ; i <= n ; i ++){
		a[i] = 0;
	}
}
struct SCC {
    int n;
    std::vector<std::vector<int>> adj;//邻边
    std::vector<int> stk;//存储同一个SCC
    std::vector<int> dfn, low, bel;//dfn : dfs的时间戳 low : 子树能跳到的最上方的点 bel : 结点位于哪块强连通分量上 
    int cur, cnt;
    
    SCC() {}
    SCC(int n) {
        init(n);
    }
    
    void init(int n) {
        this->n = n;
        adj.assign(n, {});
        dfn.assign(n, -1);
        low.resize(n);
        bel.assign(n, -1);
        stk.clear();
        cur = cnt = 0;
    }
    
    void addEdge(int u, int v) {
        adj[u].push_back(v);
    }
    
    void dfs(int x , int fa) {
        dfn[x] = low[x] = cur++;
        stk.push_back(x);
        
        for (auto y : adj[x]) {
        	if(y == fa) continue;
            if (dfn[y] == -1) {
                dfs(y , x);
                low[x] = std::min(low[x], low[y]);
            } else if (bel[y] == -1) {
                low[x] = std::min(low[x], dfn[y]);
            }
        }
        
        if (dfn[x] == low[x]) {
            int y;
            do {
                y = stk.back();
                bel[y] = cnt;
                stk.pop_back();
            } while (y != x);
            cnt++;
        }
    }
    
    std::vector<int> work() {
        for (int i = 0; i < n; i++) {
            if (dfn[i] == -1) {
                dfs(i , -1);
            }
        }
        return bel;
    }
};
struct HLD {//轻重链剖分
    int n;
    std::vector<int> siz, top, dep, parent, in, out, seq , val;//子树大小 所在重链的顶部节点 深度 父亲 子树DFS序的起点 子树DFS序的终点
    std::vector<std::vector<int>> adj;
    int cur = 1;
    HLD() {}
    HLD(int n) {
        init(n);
    }
    void init(int n) {
        this->n = n;
        siz.resize(n);
        top.resize(n);
        dep.resize(n);
        parent.resize(n);
        in.resize(n);
        out.resize(n);
        seq.resize(n);
        val.assign(n , 0);
        cur = 0;
        adj.assign(n, {});
    }
    void addEdge(int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    void work(int root = 1) {
        top[root] = root;
        dep[root] = 0;
        parent[root] = -1;
        dfs1(root);
        dfs2(root);
    }
    void dfs1(int u) {
        if (parent[u] != -1) {
            adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u]));
        }
        siz[u] = 1;
        for (auto &v : adj[u]) {
            parent[v] = u;
            dep[v] = dep[u] + 1;
            dfs1(v);
            siz[u] += siz[v];
            if (siz[v] > siz[adj[u][0]]) {
                std::swap(v, adj[u][0]);
            }
        }
    }
    void dfs2(int u) {
        in[u] = ++cur;
        seq[in[u]] = u;
        for (auto v : adj[u]) {
            top[v] = v == adj[u][0] ? top[u] : v;
            dfs2(v);
            val[u] += val[v];
        }
        out[u] = cur;
    }
    int lca(int u, int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] > dep[top[v]]) {
                u = parent[top[u]];
            } else {
                v = parent[top[v]];
            }
        }
        return dep[u] < dep[v] ? u : v;
    }
    
    int dist(int u, int v) {
        return dep[u] + dep[v] - 2 * dep[lca(u, v)];
    }
    
    int jump(int u, int k) {
        if (dep[u] < k) {
            return -1;
        }
        
        int d = dep[u] - k;
        
        while (dep[top[u]] > d) {
            u = parent[top[u]];
        }
        
        return seq[in[u] - dep[u] + d];
    }
    
    bool isAncester(int u, int v) {//是否为祖先
        return in[u] <= in[v] && in[v] < out[u];
    }
    
    int rootedParent(int u, int v) {
        std::swap(u, v);
        if (u == v) {
            return u;
        }
        if (!isAncester(u, v)) {
            return parent[u];
        }
        auto it = std::upper_bound(adj[u].begin(), adj[u].end(), v, [&](int x, int y) {
            return in[x] < in[y];
        }) - 1;
        return *it;
    }
    int rootedSize(int u, int v) {
        if (u == v) {
            return n;
        }
        if (!isAncester(v, u)) {
            return siz[v];
        }
        return n - siz[rootedParent(u, v)];
    }
    
    int rootedLca(int a, int b, int c) {
        return lca(a, b) ^ lca(b, c) ^ lca(c, a);
    }
};
void solve() 
{
	int n , m;
	cin >> n >> m;
	SCC scc(n + 5);
	pair<int,int>p[m];
	for(int i = 0 ; i < m ; i ++){
		int u , v;
		cin >> u >> v;
		scc.addEdge(u , v);
		scc.addEdge(v , u);
		p[i].x = u;
		p[i].y = v;
	}
	vector<int>v = scc.work();
	int ma = -1;
	for(int i = 1 ; i <= n ; i ++){
		ma = max(ma , v[i]);
	}
	HLD hld(ma + 5);
	for(int i = 0 ; i < m ; i ++){
		int u = v[p[i].x] , x = v[p[i].y];
		if(u == x) continue;
		hld.addEdge(u , x);
	}
	for(int i = 1 ; i <= n ; i ++){
		hld.val[v[i]]++;
	}
	hld.work();
	int ans = n * (n - 1) / 2;
	for(int i = 2 ; i <= ma ; i ++){
		ans = min(ans , hld.val[i] * (hld.val[i] - 1) / 2 + (n - hld.val[i]) * (n - hld.val[i] - 1) / 2);
	}
	cout << ans << endl;
}            
signed main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout.precision(10);
    int t=1;
	cin>>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值