At409 ABCDE

A.Conflict


原题链接

题意简述

寻找两个字符串中都是 \(o\) 的位置

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int main(){
	cin.tie(0)->ios::sync_with_stdio(false);
	int n;cin>>n;
	string s,t;cin>>s>>t;
	s="&"+s;t="&"+t;
	for(int i=1;i<=n;i++){
		if(s[i]=='o'&&t[i]=='o') return cout<<"Yes"<<endl,0;
	}
	cout<<"No"<<endl;
	return 0;
} 

B.Citation


原题链接

题意简述

寻找数组中大于 \(i\) 的一个出现次数大于 \(i\) 的第一个数

解题思路

听着就很单调,直接二分

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int n;
bool isok(const vector<int>&a,int mid){
	int cnt=0;
	for(int i=1;i<=n;i++){
		cnt+=(a[i]>=mid);
	}
	return cnt>=mid;
}
int main(){
	cin.tie(0)->ios::sync_with_stdio(false);
	cin>>n;
	vector<int>a(n+1);
	for(int i=1;i<=n;i++) cin>>a[i];
	int l=0,r=n;
	while(l<=r){
		int mid=l+r>>1;
		if(isok(a,mid)) l=mid+1;
		else r=mid-1;
	}
	cout<<l-1<<endl;
	return 0;
} 

C.Equilateral Triangle


原题链接

题意简述

给定一个周长为 \(l\) 的圆,然后给定任意整数值 \(d_i\),表示距离第i-1个点的距离,求解圆上等边三角形的个数

解题思路

数据范围十分小,对每个值统计 mod l 时在圆上的位置,然后遍历 [0,l-1] 的每个数值统计当前位置与后两个位置可以构成等边三角形的个数,注意每个等边三角形被三个顶点统计了三次,答案除以3即可。

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const int N=3e5+5;
ll mp[N];
int main(){
	cin.tie(0)->ios::sync_with_stdio(false);
	int n,l;
	cin>>n>>l;
	if(l%3) return cout<<0<<endl,0;
	int t=0;
	mp[t]++;
	for(int i=1,x;i<n;i++) {
		cin>>x;
		t=(t+x)%l;
		mp[t]++;
	}
	int d=l/3;
	ll ans=0;
	for(int i=0;i<l;i++) ans+=mp[i]*mp[(i+d)%l]*mp[(i+d*2)%l];
	cout<<ans/3<<endl;
	return 0;
} 

D.String Rotation


原题链接

题意简述

给你一个字符串,你可以对其进行一次以下操作,选取一个位置 \(l_i\),然后选取一个位置 \(r_i\) ,在 \(r_i\) 的右边插入一个第 \(l_i\) 的字符,然后删除原先第 \(l_i\) 的字符。
求操作后字典序最小的字符串是什么?

解题思路

贪心的思考,某次操作的效果对字典序减小,当且仅当某一位字符后面一位字符比当前字符大,同时字典序要尽可能地小,那么按权重考虑必定是从前往后遍历。这样,我们就可以注意到一个结论,对于每一个位置,它的字典序想要尽可能小,一定是把 \(s_i <s_{i+1}\) 的第一个位置 \(i\) 的字符丢到,第 \(i\) 个位置后面 \(s_j(s_j>s_i)\) 的第一个位置前面,直接 \(O(n)\)从第一个位置找到最后一个位置,找到后再输出 \(s_i\),一直找不到 \(s_i\) 就最后输出即可。

AC code

void solve(){
    int n;cin>>n;
    string s;cin>>s;
    char c;
    int idx=n;
	for(int i=0;i<n;i++){
        if(s[i]>s[i+1]){
            idx=i;
            c=s[i];
            break;
        }
        else cout<<s[i];
    }
    bool find_leq=0;
    for(int i=idx+1;i<n;i++){
        if(s[i]>c&&!find_leq){
            cout<<c;
            cout<<s[i];
            find_leq=1;
        }
        else cout<<s[i];
    }
    if(!find_leq) cout<<c;
    cout<<endl;
}

E.Pair Annihilation


原题链接

题意简述

给定一棵无根树,每条边有一个非负的权值 \(w\),每个点上留着一个或正或负的电子,允许以下操作,把某个节点的一个正电子或负电子沿着边消耗边权 \(w\) 的代价移动到另一个节点,当正负电子相遇时发生湮灭,较多电子消耗较少电子的量,较少电子消失。求湮灭所有电子的最小代价?
题目保证给定树上正负电子和是0

解题思路

考虑末状态,最后子树权值和一定是根节点权值 \(q\)与与根相邻的某个子树权值 \(-q\) 相加后为 0,
则选取与根相邻的子树的根作为根节点 换根的代价是 \(val=-w*abs(q)+w*abs(-q)=0\)
所以选择任何节点作为根的代价是一样的。
这样考虑随机选择一个节点作为根节点进行树形dp,对于每个正负电子,我们一定希望他们尽可能早的被湮灭,那么对于某个电子只要一直朝向根节点汇聚,这个过程因为每个可相遇的正负电子一定在最早的时刻相遇了,所以湮灭它一定是最小的代价的。记每个点的权值是 \(f\) ,有转移 $ f_u=\sum_{v \in u} f_v+abs(q_v)·w_{u,v}$。

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const int N=2e5+5;
int a[N];
struct node{
    int u;ll w;
};
vector<node>G[N];
int nums[N];
ll f[N];
void dfs(int u,int fa){
    nums[u]=a[u];
    for(auto &[v,w]:G[u]){
        if(v==fa) continue;
        dfs(v,u);
        nums[u]+=nums[v];//子树权值和
        f[u]+=f[v]+abs(nums[v])*w;//当前子树代价和
    }
}
int main(){
    int n;cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<n;i++){
        int x,y;ll w;
        cin>>x>>y>>w;
        G[x].push_back({y,w});
        G[y].push_back({x,w});
    }
    dfs(1,0);
    cout<<f[1]<<endl;
    return 0;
}
posted @ 2025-06-08 01:40  usedchang  阅读(13)  评论(0)    收藏  举报