The 2023 ICPC Asia Hefei Regional Contest (The 2nd Universal Cup. Stage 12: Hefei)

题目链接:The 2023 ICPC Asia Hefei Regional Contest (The 2nd Universal Cup. Stage 12: Hefei)

F. Colorful Balloons

解析:
直接用map计下每个字符串出现的次数,判断cnt/n有无大于50即可。

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e4 + 7;
const int mod =1e9+7;
void solve() {
	int n;
	cin>>n;
	map<string,double>mp;
	for (int i=1;i<=n;i++){
		string s;
		cin>>s;
		mp[s]+=1;
	}
	for (auto it:mp){
		string s=it.first;
		double cnt=it.second;
		if (cnt/n*1.0>0.5){
			cout<<s<<"\n";
			return;
		}
	}
	cout<<"uh-oh\n";
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T=1;
	// T = 1;
//	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

E. Matrix Distances

解析:
这道题我直接用原题题解了,用文字不好解释。
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
typedef pair<int, int> pii;

int cal(vector<int> &v)
{
    int ans = 0;
    if (v.size() == 1)
        return 0;
    int n = v.size() - 1;
    int num = n;
    int f = 0,ff=0;
    //cout << n << "-----\n";
    if (n & 1)
        f = 1;
    for (int i = 1; i < v.size(); i++)
    {
        //cout << i << ' ' << num << " " << n << '\n';
        ans += (v[i] - v[i - 1]) * num;
        if (n - 2 >= 0 && !ff)
        {
            num = num + n - 2;
            n -= 2;
        }
        else
        {
            ff=1;
            // 奇数
            if (f)
            {
                num-=n;
                n+=2;
            }
            else {
                n+=2;
                num-=n;
            }
        }
    }
    //cout << "----\n";
    return ans * 2;
}

void solved()
{
    int n, m;
    cin >> n >> m;
    map<int, vector<pii>> mp;
    int a[n + 10][m + 10];
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
            mp[a[i][j]].push_back({i, j});
        }
    }
    for (auto t : mp)
    {
        auto v = t.second;
        vector<int> x, y;
        for (auto u : v)
        {
            x.push_back(u.first);
            y.push_back(u.second);
        }
        sort(x.begin(), x.end());
        sort(y.begin(), y.end());
        ans += cal(x);
        ans += cal(y);
    }
    cout << ans << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int T;
    T = 1;
    // cin >> T;
    while (T--)
    {
        solved();
    }
    return 0;
}

J. Takeout Delivering

解析:这道题需要找一条路径使得拥塞度最高两条边拥塞度之和最小。
我们找一条路径的最大值很好找,用dijsktra。
d[i]存从1到每个点时当前路径的最大值的最小值。
但是我们还差次大值,假如u-v这条边,这时w是当前路径的最大值,那么次大值会出现在哪里呢,1-u?1-v?当然也可能是n-u,n-v。
所以我们还需要用fd[i]存从n到每个点当前路径最大值的最小值。
然后枚举每条边的权值,判断是不是最大值,如果是,则找max(min(1-u,n-u),min(1-v,n-v))。
为什么找min(1-u,n-u)呢。
因为不知道哪一段没有包括u-v这一段,而取max是因为不知道次小值出现在u还是v的另一边。

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 2e6 + 7;
const int mod =1e9+7;
int d[N],fd[N];
bool vis[N];
int n,m;
vector<pair<int,int>>e[N];
struct node {
	int x,y,z;
} node[N];
void dijsktra(int x,int *dis) {
	for (int i=1; i<=n; i++) {
		vis[i]=0;
		dis[i]=1e18;
	}
	priority_queue<pair<int,int>>q;
	dis[x]=0;
	q.push({0,x});
	while (!q.empty()) {
		int w=-q.top().first;
		int u=q.top().second;
		q.pop();
		if (vis[u]) {
			continue;
		}
		vis[u]=1;
		for (auto v:e[u]) {
			int to=v.first;
			int ans=v.second;
			if (dis[to]>max(w,ans)) { //传递最大值
				dis[to]=max(w,ans);
				q.push({-dis[to],to});
			}

		}
	}

}
void solve() {
	cin>>n>>m;
	int maxx=1e18;
	for (int i=1; i<=m; i++) {
		int x,y,z;
		cin>>x>>y>>z;
		if (x>y) {
			swap(x,y);
		}
		if (x==1&&y==n) {
			maxx=min(maxx,z);
		}
		e[x].push_back({y,z});
		e[y].push_back({x,z});
		node[i].x=x;
		node[i].y=y;
		node[i].z=z;
	}
	dijsktra(1,d);
	dijsktra(n,fd);
	for (int i=1; i<=m; i++) {
		//	cout<<"距离1的最大值的最小值"<<i<<" "<<d[i]<<"\n";
		//	cout<<"距离n的最大值的最小值"<<i<<" "<<fd[i]<<"\n";
		int u=node[i].x;
		int v=node[i].y;
		int w=node[i].z;//假设当前这个是最大边,后面可以通过判断得知
		int ans=min(max(d[u],fd[v]),max(d[v],fd[u]));//找次大边
		if (ans<=w) {
			maxx=min(maxx,ans+w);
		}
	}
	cout<<maxx<<"\n";
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T=1;
	// T = 1;
//	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

G. Streak Manipulation

解析:
因为要需要求第k条最长条纹,而题目这个条纹可以变化,我们可以用二分来固定条纹长度。
接下来判断是否可以构造出条纹满足要求。
我们可以采用DP,dp[i][j][0/1]表示到i点时如果要使大于mid的条纹到达j条最小需要的修改次数,i表示0/1表示该点是否成为断点的情况。
我们可以先用前缀和处理一下0的数量,这样后面可以直接知道一段中达到mid需要修改多少条条纹
DP推导式:

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
int n,m,k;
int pre[N];
int dp[N][7][3];
string s;
int check(int x) {
	for (int i=1; i<=n; i++) {
		for (int j=0; j<=k; j++) {
			if (s[i]=='0') {
				dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]);//把当前这层设为结尾,后面用断点信息
			} else {
				dp[i][j][0]=dp[i-1][j][0];
			}
			dp[i][j][1]=dp[i-1][j][1];
			if (i>=x) {
				dp[i][j][1]=min(dp[i][j][1],dp[i-x][j-1][0]+pre[i]-pre[i-x]);
			}
			if (x==3) {
				//	cout<<"i: "<<i<<" j: "<<j<<" dp[i][j][0]: "<<dp[i][j][0]<<" dp[i][j][1]: "<<dp[i][j][1]<<"\n";
			}
		}
	}
	if (dp[n][k][1]<=m) {
		return 1;
	} else {
		return 0;
	}

}
void solved() {
	cin>>n>>m>>k;
	cin>>s;
	s=' '+s;
	for (int i=0; i<=n; i++) {
		for (int j=0; j<=k; j++) {
			dp[i][j][0]=1e18;
			dp[i][j][1]=1e18;
		}
	}
	dp[0][0][0]=0;
	for (int i=1; i<=n; i++) {
		pre[i]=pre[i-1];
		if (s[i]=='0') {
			pre[i]+=1;
		}
	}
	int l=-1,r=1e9;
	while (l+1<r) {
		int mid=(l+r)/2;
		if (check(mid)) {
			l=mid;
		} else {
			r=mid;
		}
	}
	if (l==0) {
		cout<<"-1\n";
		return;
	}
	cout<<l<<"\n";
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T=1;
	// T = 1;
//	cin >> T;
	while (T--) {
		solved();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值