2024牛客6

B.Cake 2

题意:
给定一个正n边形,每个顶点与距离k的顶点相连
问最后一共被切成多少个图形

题解:
手动画图,找规律,k*2=n时,答案就是n,被切成n份
其他情况答案是 n ∗ m i n ( n , n − k ) + 1 n*min(n,n-k)+1 nmin(n,nk)+1

代码:

#include<bits/stdc++.h>
using namespace std;
typedef __int128 i128;
typedef long long ll;
typedef double db;

const db PI = acos(-1);
typedef array<ll, 2> PII; // vector<PII> a(n + 1);
const ll inf = 2e18 + 10;
const int mod = 998244353;
const int maxn = 2e5 + 10;
bool multi = 0;

void Solve() {
    ll n, k; cin >> n >> k;
    if(n % 2 == 0 && k == n / 2) cout << n << "\n";
    else {
        if(k >= (n + 1) / 2) k = n - k;
        cout << n * k + 1 << "\n";
    }
}


signed main() {
    // freopen("test.in","r",stdin);  
    // freopen("code.out","w",stdout);    
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    ll T = 1;
    if(multi) cin >> T;
    while(T -- ) {
        Solve();
    }
    return 0;
}

A.Cake

题意:
给定一棵树,每条边有值0或1,Grammy 和Oscar轮流从根节点选一条边走,直到根节点,记录走过的01串。
然后Oscar把蛋糕分为m份(01串的长度)。1代表Grammy选一份,0代表Oscar选一份。
问两人都想拿最大比例的蛋糕,问最后Grammy能拿的比例。

题解:

由于是由Oscar分配,他会尽量让自己多拿,例如011就可以把蛋糕全分在第一份,就可以全部拿走了。
1100,可以把蛋糕分为4份,可以拿一半,发现我们需要找的是01串的0的前缀比例最大的时候。

现在考虑两人在树上得到的01串。
轮到奇数次选的时候Grammy想要让0的前缀比例最小。
轮到偶数次选的时候Oscar想要让0的前缀比例最小大。
就先dfs每个节点0的前缀最大和最小的的节点,两人轮流选择。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef __int128 i128;
typedef long long ll;
typedef double db;

const db PI = acos(-1);
typedef array<ll, 2> PII; // vector<PII> a(n + 1);
const ll inf = 2e18 + 10;
const int mod = 998244353;
const int maxn = 2e5 + 10;
bool multi = 1;

struct node {
    ll u, ze, on;
};

void dfs(ll x, ll fa, vector<vector<PII>> &e, ll ff, vector<db> &ans, ll las) {
    db anss = 0;
    for(auto p : e[x]) {
        ll y = p[0], k = p[1];
        if(y == fa) continue;
        ll f = ff ^ 1;
        dfs(y, x, e, f, ans, k);
        if(ff) {
            if(anss == 0) anss = ans[y];
            else anss = max(anss, ans[y]);
        } else {
            if(anss == 0) anss = ans[y];
            anss = min(anss, ans[y]);
        }
    }
    if(anss == 0) return ;
    if(!las) {
        if(anss < ans[x]) ans[x] = anss;
    } else {
        ans[x] = anss;
    }
}

void Solve() {
    ll n; cin >> n;
    vector<vector<PII>> e(n + 1);
    vector<db> ans(n + 1);
    vector<bool> vis(n + 1);
    for(ll i = 1; i < n; i ++ ) {
        ll x, y, k; cin >> x >> y >> k;
        e[x].push_back({y, k});
        e[y].push_back({x, k});
    }

    queue<node> q;
    q.push((node){1, 0, 0});
    while(!q.empty()) {
        node d = q.front(); q.pop();
        ll u = d.u, ze = d.ze, on = d.on;
        for(auto p : e[u]) {
            ll v = p[0], k = p[1];
            if(vis[v] == true) continue;
            else vis[v] = true;
            if(k == 1) {
                ans[v] = (db)(on + 1) / (db)(on + ze + 1); 
                q.push((node){v, ze, on + 1});
            }
            else {
                ans[v] = (db)on / (db)(on + ze + 1); 
                q.push((node){v, ze + 1, on});
            }
        }
    }
    dfs(1, 1, e, 1, ans, 0);
    db anss = 0;
    for(auto p : e[1]) {
        anss = max(ans[p[0]], anss);
    }
    cout << fixed << setprecision(10);
    cout << anss << "\n";
}

signed main() {
    // freopen("test.in","r",stdin);  
    // freopen("code.out","w",stdout);    
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    ll T = 1;
    if(multi) cin >> T;
    while(T -- ) {
        Solve();
    }
    return 0;
}

D.Puzzle: Wagiri

题意:
给你一个无向连通图,每条边有名称Qie和Lun。
现在可以删掉一些边满足以下条件:
·这个图的Qie边不在任何循环上。
·这个图的Lun边一定在循环上。
·图一定是连通的。

问你能不能实现,如果能,保留哪些边。

题解:
把两种边分开存储,在Lun边组成的图中,我们要找环,用tarjan算法,把成环的边加入答案,还有用并查集维护,最后遍历Qie边,把没有连通的节点连在一起,加入最后答案是连通的,则有答案,否则没有

代码:

#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=3e5;
int n,m;
pair<int,int>b[N],d[N];
set<pair<int,int>>ans;

vector <int>e[N],st;
int p[N],x,y;
int low[N],dfn[N];
int cnt;
int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void dfs(int now, int pre) {
    low[now] = dfn[now] = ++cnt;
    st.push_back(now);
    
    for (auto i: e[now]) {
        if (i == pre) continue;
        if (!dfn[i]) {
            dfs(i, now);
            low[now] = min(low[now], low[i]);
        } else
            low[now] = min(low[now], low[i]);
    }
    if (low[now] == dfn[now]) {
        while (st.back() != now) {
        	x=find(st.back());
        	y=find(now);
        	if(x>y)swap(x,y);
        	p[y]=find(x);
            st.pop_back();
        }
        st.pop_back();
    }
}

void solve()
{
	cin>>n>>m;
	int u,v;
	string ss;
	int t=0;
	for(int i=1;i<=n;i++){
		p[i]=i;
	}
	int t2=0;
	for(int i=1;i<=m;i++){
		cin>>u>>v;
		cin>>ss;
		if(ss[0]=='L'){
			e[u].push_back(v);
			e[v].push_back(u);
			d[t2++]={u,v};
		}
		else {
			b[t++]={u,v}; 
		}
	}
	for(int i=1;i<=n;i++){
		if(dfn[i]==0){
			dfs(i,0);	
		}
	}
	
	for(int i=0;i<t2;i++){
		x=find(d[i].first);
		y=find(d[i].second);
		if(x>y)swap(x,y);
		if(x==y){
			ans.insert(d[i]);
		}
	}
	
	for(int i=0;i<t;i++){
		x=find(b[i].first);
		y=find(b[i].second);
		if(x>y)swap(x,y);
		if(x!=y){
			ans.insert(b[i]);
			p[y]=x;
		}
	}
	for(int i=1;i<=n;i++){
		x=find(i);
		if(p[x]!=1){
			cout<<"NO\n";
			return ;
		}
	}
	cout<<"YES\n";
	cout<<ans.size()<<'\n';
	for(;ans.size()>0;){
		auto an=*ans.begin();
		cout<<an.first<<' '<<an.second<<'\n';		
		ans.erase(ans.begin());
	}
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int T=1;
//    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值