2024 暑假友谊赛-热身1
知识点
1.Floyd算法的核心代码
//floyd算法计算到达两点的最小代价
for(int k=0;k<=n;k++)//n是节点数
{
for(int i=0;i<n;i++)//每加一个节点都要枚举图看看有没有可以被更新的
{
for(int j=0;j<n;j++) if(dp[i][j]>dp[i][k]+dp[k][j]) dp[i][j]=dp[i][k]+dp[k][j];
}
}
题解
D - Wall
1.使用floyd算法计算一下每个点到每个点到最小花费即可,然后输入查询相加即可
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
void solve()
{
int h,w; cin>>h>>w;
int dp[10][10];
for(int i=0;i<=9;i++)
{
for(int j=0;j<=9;j++) cin>>dp[i][j];
}
//floyd算法计算到达两点的最小代价
for(int k=0;k<=9;k++)
{
for(int i=0;i<=9;i++)
{
for(int j=0;j<=9;j++) if(dp[i][j]>dp[i][k]+dp[k][j]) dp[i][j]=dp[i][k]+dp[k][j];
}
}
int ans=0;
//输入查询相加即可
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
{
int x;
cin>>x;
if(x>=0) ans+=dp[x][1];
}
}
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
C - Minimization
1.这题我们思维定式会去找最小值的位置,其实跟最小值的位置没关系,因为一定会遍历到这个最小值,所以只要计算到最右边界的次数即可
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
void solve()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
}
int d=0,res=0;
while(d<n)
{
if(d==0) d+=m;
else d+=m-1;
res++;
}
cout<<res;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
Linear Approximation
1.令ci=ai-i;则题目就转化为求abs(ci-b)的和,那么只有当b为差值的中位数,对总和的贡献最小
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
void solve()
{
int n;
cin>>n;
vector<int>ve(n+1);
for(int i=1;i<=n;i++) {
cin>>ve[i];
ve[i]=ve[i]-i;
}
sort(ve.begin()+1,ve.end());
int temp=ve[n/2+1];
int ans=0;
for(int i=1;i<=n;i++)
{
ans+=abs(ve[i]-temp);
}
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
C. Brutality
1.按题意来模拟,就是找几个连续字母代表的数字的最大和,但不能超过k次,也就是几个连续字母这段区间的前k个值(从大到小)的和,不足k个则全加进去
2.一段一段区间来处理,会使代码更加简洁快速
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
void solve()
{
int n,m;
cin>>n>>m;
vector<int>ve(n);
for(int i=0;i<n;i++)
{
cin>>ve[i];
}
string s; cin>>s;
int ans=0;
for(int i=0;i<n;i++)
{
//遍历到几个连续相同的就进行一次处理
int j=i;
vector<int>fi;
while(j<n&&s[i]==s[j])
{
fi.push_back(ve[j]);
j++;
}
sort(fi.rbegin(),fi.rend());//从大到小排序
//accumulate函数中的这个min最关键,这样可以避免你还要重新去开几个查询的数组来找值的和
ans+=accumulate(fi.begin(),fi.begin()+min(m,(int)fi.size()),0);
i=j-1;
}
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
D - Equal Cut
1.我们把题目想象成,我们在一组已经排列好的数里面,选择3个位置放挡板
2.首先,我们肯定要枚举第二块挡板,先把这些数分为左右两个区间,然后在左右区间里面,在分别枚举一块合适的挡板
3.那么什么情况下最合适呢,当左右区间里的两个区间的绝对值差值最小是最合适的,因为题目要我们求最大和区间-最小和区间的值,也就是要让最小区间和尽量大,最大区间和尽量小,这样差值才会更小,所以当区间绝对值差值最小的时候,就可以满足了
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
int sum[200005];
int js(int l,int r)//求区间的和
{
return sum[r]-sum[l-1];
}
void solve()
{
int n; cin>>n;
vector<int>ve(n+1);for(int i=1;i<=n;i++) cin>>ve[i];
for(int i=1;i<=n;i++) sum[i]=ve[i]+sum[i-1];
//枚举第二刀把其分为L R区间
int l=1,r=3;
int ans=1e9;
for(int i=2;i<=n-2;i++)//总共有n个元素第二刀最多切到n-2
{
while(l+1<i&&abs(js(1,l)-js(l+1,i))>=abs(js(1,l+1)-js(l+2,i))) l++;
//相当于你在L这个区间 找位置切,直到找到L里左右区间差值最小
//差值最小能够保证我们前面有一个使减数尽量大的区间
while(r+1<n&&abs(js(i+1,r)-js(r+1,n))>=abs(js(i+1,r+1)-js(r+2,n))) r++;
//在R区间是同理的
set<int>se;
//set自动从小到大排序
se.insert(js(1,l));
se.insert(js(l+1,i));
se.insert(js(i+1,r));
se.insert(js(r+1,n));
ans=min(ans,abs(*se.begin()-*prev(se.end())));//prev用来获取最后一个值的地址
}
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
//cin>>t;
while(t--) solve();
return 0;
}
E. Air Conditioners
1.对于一个位置,如果我们暴力的思考,是要去检查很多个空调和跟它的距离的,那么怎么让当前位置的决定因素变少呢?
2.我们可以这么思考,如果对于当前位置,我只考虑其左边只有一个空调,那么这个位置的温度是不是就取决于这个空调和其到这个空调的距离了,但是如果左边不止一个空调呢?所以我们应该把参照变成这个位置的上一个位置的温度
3.在只考虑左边的空调的情况下,当前位置的温度=min(原本位置的温度,上一个位置的温度+1),我们把题目没给温度的位置全赋值为1e10,右边同理,不过应该从右往左。
4.那么答案就是min(l【i】,r【i】)
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define forn(i,n) for(int i=0;i<(int)n;i++)
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,-1,0};
int dy[]={-1,0,0,1};
void solve()
{
int n,k; cin>>n>>k;
vector<int>a(k),t(k);
for(int i=0;i<k;i++) cin>>a[i];
for(int i=0;i<k;i++) cin>>t[i];
vector<int>c(n,1e10);
for(int i=0;i<k;i++) c[a[i]-1]=t[i];//把空调放进对应的位置
//l数组存的是当只算当前位置和当前位置左边的空调,i位置的温度
//r数组存的是当只算当前位置和当前位置右边的空调,i位置的温度
vector<int>l(n,1e10),r(n,1e10);
int p=1e10;
for(int i=0;i<n;i++)
{
//当我们只考虑一个位置左边的空调温度时,这个位置的温度
//要么当前位置没有空调温度是上一个位置的温度+1,要么这个位置有空调则温度就是空调的温度
p=min(p+1,c[i]);
l[i]=p;
}
//这里要从右开始,因为我们当前的位置要由其右边的温度来决定
p=1e10;
for(int i=n-1;i>=0;i--)
{
p=min(p+1,c[i]);
r[i]=p;
}
for(int i=0;i<n;i++) {
cout<<min(l[i],r[i])<<" ";
}
cout<<endl;
//对了注意一个点,有空调的位置它的温度并不是就是这个空调原本的温度,也是会变的
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
posted on 2024-07-12 20:56 swj2529411658 阅读(36) 评论(0) 收藏 举报
浙公网安备 33010602011771号