比赛链接:Dashboard - Codeforces Round #792 (Div. 1 + Div. 2) - Codeforces
A: 思维
题意:Alice和Bob在玩游戏,每次等Alice交换两个不同位置的数后,Bob就会删除最后一个位置上的数,当最终只剩下一个数后,游戏结束。保证使这个数最小,问最小是多少?
分析:
特判一下。如果数的长度为2,那么Alice必须交换一次,Bob才能删除。所以ans就是第二个数。
一般情况:无论怎么操作,Alice是一定可以把最小值放在最前面。
代码:
#include<bits/stdc++.h>
#define all(v) v.begin(),v.end()
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pi acos(-1)
using namespace std;
const int INF=0x3f3f3f3f;
const int N=2e7+10;
typedef pair<int,int>PII;
inline void solve(){
string s;cin>>s;
if(s.size()==2){
cout<<s[1]<<"\n";return;
}
int minn=INF;
for(int i=0;i<s.size();i++){
minn=min(minn,(int)s[i]-'0');
}
cout<<minn<<"\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
B:构造
题意:给定三个数a,b,c。使其满足题中的三个条件的x,y,z。任意输出x,y,z
分析:前置芝士:a<b, a % b= a
所以我们可以显然构造出:x=a+b+c,y=b+c,z=c。
代码:
#include<bits/stdc++.h>
#define all(v) v.begin(),v.end()
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pi acos(-1)
using namespace std;
const int INF=0x3f3f3f3f;
const int N=2e7+10;
typedef pair<int,int>PII;
inline void solve(){
int a,b,c;cin>>a>>b>>c;
cout<<a+b+c<<" "<<b+c<<" "<<c<<"\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
C:模拟+排序
题意:给定一个矩阵,问是否只交换矩阵中的两列(可以是相同的两列),使得矩阵中每行的元素都是非降的。
思路:我们先给每一行进行排序,然后我们将改变后的矩阵跟原矩阵进行对比。找出错位的位置,然后把这两列交换,如果交换后满足条件,就输出这两列,否则就输出-1.
ps:如果错位的个数多于两个,那么不管交换哪两列,都不会满足条件(具体看代码)
代码:
#include<bits/stdc++.h>
#define all(v) v.begin(),v.end()
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pi acos(-1)
using namespace std;
const int INF=0x3f3f3f3f;
const int N=2e7+10;
typedef pair<int,int>PII;
int n,m;
//用于交换矩阵中的两列
inline void Swap(int x,int y,vector<vector<int>>&a){
for(int i=0;i<n;i++) swap(a[i][x],a[i][y]);
}
inline void solve(){
cin>>n>>m;
vector<vector<int>>a(n,vector<int>(m));/*这里做解释一下:这里相当于重新定义了一下二维数组:表示:vector类型的a数组,数组每个值是vector类型,大小是:a(n,vector<int>(m))是指有n行,每行有m个元素*/
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>a[i][j];
}
}
vector<vector<int>>b=a;//用矩阵b复制矩阵a
set<int>se;
bool ok=false;
for(int i=0;i<n;i++){
sort(all(b[i]));//每行先进行排序
for(int j=0;j<m;j++){//与矩阵a对比每列的元素
if(a[i][j]!=b[i][j]) se.insert(j);//错位就放进set
if(se.size()==2){//等于2就可以终止循环了,因为多于2,还是只能交换一次(题意)
ok=true; break;
}
}
if(ok) break;//加快循环操作
}
if(!ok){//如果没有错位,即:原始矩阵本就满足条件的情况下,随便输出两个相同的列即可
cout<<"1 1\n";return;
}
vector<int>pos;//用vector接受set容器中的值
for(auto i:se) pos.push_back(i);
Swap(pos[0],pos[1],a);//交换列
for(int i=0;i<n;i++){//判断是否满足条件
for(int j=1;j<m;j++){
if(a[i][j]<a[i][j-1]){
cout<<"-1\n";return;
}
}
}
cout<<pos[0]+1<<" "<<pos[1]+1<<"\n";//为什么+1?因为下标是从0开始的
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
D:贪心
题意:有 n 个陷阱,每个陷阱造成 ai 点伤害,最多跳过 k 个陷阱,但如果选择跳过这个陷阱的话,后面的每个陷阱的伤害都会加 1,问最少伤害是多少
吐槽:这题相通了很简单,想不通就一愣一愣的。
这里参考的是ygg的题解:
Codeforces Round #792 (Div. 1 + Div. 2) D(贪心) E(贪心) - 知乎
分析:先考虑。最优的方案肯定是把给定的次数给跳完。问题就在于,每跳一个,跳过的位置后面的伤害就会+1。如何跳?
错误方法:直接从后往前面选择k个陷阱跳完——然后就g啦!
正确方法: 假设我们跳过的第一个陷阱为i,那么对答案的贡献就是a[i](这里的贡献是指,总和减去a[i])。但是后面的伤害都会+1,所以对于单个陷阱i而言,它对答案的贡献为 a[i]+(n-i)。
a[i]+(n-i):跳过点i后会对答案贡献原始的a[i]伤害+(跳完后)后面的(n-i)
跳完第一个陷阱,后面还有k-1个跳过陷阱的机会,所以该点对答案的贡献同理:伤害减少k-1。
k-2:伤害减少k-2。然后我们就可以推出仅跟k相关的减少伤害量:
根据前面的推理:每个位置对于伤害的贡献为 -a[i]+(n-i)=n-(a[i]+i)
令v[i]=n-(a[i]+i),然后选择k最小的k个即可。具体看代码:
代码:
#include<bits/stdc++.h>
#define all(v) v.begin(),v.end()
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pi acos(-1)
using namespace std;
const int INF=0x3f3f3f3f;
const int N=2e7+10;
typedef pair<int,int>PII;
int a[N];
inline void solve(){
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
vector<int>ve;
for(int i=1;i<=n;i++) ve.push_back(n-(a[i]+i));//放入每个点对答案的贡献
int ans=accumulate(a+1,a+1+n,0LL);//原始累加和
sort(all(ve));//将贡献进行排序
for(int i=0;i<k;i++) ans+=ve[i];//加每一个点对ans的贡献,选择k个点
k--;//参考k关于答案的贡献 (k-1)
//因为一旦跳过一个点,会影响后面。
ans-=(k*(1+k)/2);//减去重复点造成的伤害 1~k-1的和
cout<<ans<<"\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}