C题意:给你一个n*m的矩阵,问你能否交换两列(可以同一列)使得所有行都是非递减的。
分析:模拟
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int t;
cin>>t;
while(t--)
{
int f=0;
int l=-1,r=-1;
int n,m;
cin>>n>>m;
vector<vector<int>>a(n,vector<int>(m));//n,m范围都在1e5 但总范围不大
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>a[i][j];
}
vector<int>b=a[i],bb=a[i];
sort(bb.begin(),bb.end());
vector<int>tmp;
for(int j=0;j<m;j++)
{
if(b[j]!=bb[j])
{
tmp.push_back(j);
}
}
if(tmp.size()>=3) f=1;
else if(tmp.size()==2)
{
l=tmp[0];
r=tmp[1];
}
}
for(int i=0;i<n;i++)
{
swap(a[i][l],a[i][r]);
if(!is_sorted(a[i].begin(),a[i].end())) f=1;
}
if(f) puts("-1");
else if(l==-1) puts("1 1");
else cout<<l+1<<" "<<r+1<<endl;
}
}
D题意:你需要从左到右走过n个陷阱,每个陷阱会对你造成a[i]的伤害。你可以选择跳过最多k个陷阱,但每跳过一个陷阱,后面所有的陷阱伤害+1,问最少的伤害总和。
分析:显然跳过k个陷阱是最优的。假设我们跳过了第i个陷阱会立即受到n-i点伤害(之后都踩满),那么实际上我们多算了j点伤害(j是之后跳过的陷阱数量),多算的伤害总和为k*(k-1)/2,我们在最后减掉即可。那么跳过第i个点能规避的伤害为b[i]=a[i]-(n-i),只需最大化规避伤害的总和即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200005],b[200005];
signed main()
{
int t;
cin>>t;
while(t--)
{
int n,k;
cin>>n>>k;
int sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
b[i]=a[i]-(n-i);//跳过第i个点可以规避的伤害
}
sort(b+1,b+n+1);
reverse(b+1,b+n+1);
int ans=0;
for(int i=1;i<=k;i++)
{
ans+=b[i];
}
cout<<sum-ans-k*(k-1)/2<<endl;
}
}