2022杭电多校6

1006 F Maex

题意:
给定一颗树,树上的每个节点有一个权值,权值互不相等。定义mex(i)为以 i 为根的子树上最小的没出现的正整数。对每一个节点的权值进行构造

,求整颗树的所有节点的mex的最大值。

分析:

void dfs(int u, int fa) {
    siz[u] = 1;
    int mx = 0;
    for (int v : g[u]) {
        if (v == fa)continue;
        dfs(v, u);
        siz[u] += siz[v];
        mx = max(mx, dp[v]);
    }
    dp[u] = mx + siz[u];
}
void slove() {
    cin >> n;
    for (int i = 1; i <= n; i++)g[i].clear(), siz[i] = 0, dp[i] = 0;
    for (int i = 1; i <= n - 1; i++) {
        int u, v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    cout << dp[1] << endl;
}

1010 J Planar graph

题意:

给定一个平面图,图中有许多边把图分成了许多部分。我们能够在每个分割图的边上建立一个地下通道穿梭到另一个图。我们需要让图中每一块图都能够互相

到达,请问求出建立通道的最少数量以及字典序最小的建立通道的方式。

分析:

我们建桥的操作,可以看成删除边。

最后面可以相互联通,就是要求我们删边后,使得图没有环。

没有环就是需要是树(或者是森林)。那么这个就是个一个最小生成树(边权为1)。

要求字典序最小,我们直接倒着枚举边,这样可以使得编号大的边被保留,编号小的被删除(记录到方案中)。

#include <iostream>
#include <vector>

using namespace std;
const int N = 300010;
int n, m, p[N];
pair<int, int> e[N];

int find(int x) 
{
    return x == p[x] ? x : p[x] = find(p[x]);
}

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) p[i] = i;
    for (int i = 1; i <= m; i ++) 
        cin >> e[i].first >> e[i].second;
    vector<int> v;
    for (int i = m; i; i--) 
    {
        int a = e[i].first, b = e[i].second;
        a = find(a), b = find(b);
        if (a == b) v.push_back(i);
        else p[a] = b;
    }
    cout << v.size() << '\n';
    for (int i = v.size() - 1; ~i; i--) cout << v[i] << ' ';
    cout << '\n';
}

int main() {
    cin.tie(0)->sync_with_stdio(false);
    int T;
    cin >> T;
    while (T--) solve();
    return 0;
}

1007.Shinobu loves trip

#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define fi first
#define se second
typedef pair<int,int>PII;
const int N=2e5+10,INF=0x3f3f3f3f;
int n,m,a,P,ans;
int s[N],d[N];
int incf[N],x;
int qmi(LL a,LL k,LL p){
    int res=1;
    while(k){
        if(k&1)res=res*a%p;
        k>>=1;
        a=a*a%p;
    }
    return res;
}
vold solve(){
	cin>>P>>a>>n>>m;
	map<int,int>mp;
	int mark=1,t=0;
	while(t<N){
		if(!mp.count(mark)){
			mp[mark]=t;
			mark=mark*a%P;
			t++;
		}
	}
	for(int i=1;i<=n;i++){
		cin>>s[i]>>d[i];
		if(s[i]!=0)incf[i]=qmi(s[i],P-2);
	}
	while(m--){
		cin>>x;
		ans=0;
		if(x==0){
			for(int i=1;i<=n;i++)if(s[i]==0)ans++;
		}else{
			for(int i=1;i<=n;i++){
				if(s[i]){
					int temp=x*incf[i]%P;
					if(mp.count(temp) && mp[t]<=d[i])ans++;
				}
			}
		}
		cout<<ans<<endl;	
	}
}
signed main(){
	int T=1;
	cin>>T;
	while(T--)solve();
	return 0; 
}

1012 L Loop

题意:

给定一个长度为n的数组,你可以进行k次操作,每次操作可以把一个数拿出来,后面的数整体前移,然后选择一个点插入该数。请问必须进行k次操作的前提

下,能够使数组的字典序最大。

分析:

因为要求字典序最大 贪心 从前往后开始处理

因为只能进行k次操作 所以想到要处理前面k个相对较小的 但是并不一定是前k个!!!

比如

当k=2 时 2 3 6 5 4 就应该取得2 3

当k=2 时 2 5 3 6 5 2 就应该取得2 3

那到底应该怎么判断呢?

用单调栈即可 !!!!

后面就贪心就好

void slove() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++)cin >> a[i];
    vector<int>stk;
    priority_queue<int>del;
    for (int i = 1; i <= n; i++) {
        while (stk.size() && stk.back() < a[i] && k) {
            del.push(stk.back());
            stk.pop_back(), k--;
        }
        stk.push_back(a[i]);
    }
    vector<int>ans;
    int id = 0;
    stk.push_back(-INF), del.push(-INF);
    while (ans.size() < n) {
        if (stk[id] >= del.top())ans.push_back(stk[id++]);
        else ans.push_back(del.top()), del.pop();
    }
    for (int i = 0; i < ans.size(); i++) {
        if (i)cout << " ";;
        cout << ans[i];
    }
    cout << endl;
}
posted @ 2022-09-26 16:40  wzx_believer  阅读(30)  评论(0编辑  收藏  举报