题目链接: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;
}