【CF #792 Div1+Div2】A-E

A. Digit Minimization

题目

分析

每次操作先交换两个数再删去尾端的数,使最后剩余的数最小。

直接判断这个数大于100,每次操作都可以把最小的数留到最后,只有两位数的话只能是个位的数。

代码

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define guanliu ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const ll maxn=2e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);

int main() 
{
	guanliu;
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		if(n/100==0)
		{
			int a=n/10;
			int b=n%10;
			cout<<b<<endl;
			continue;
		}
		int ans=10;
		while(n)
		{
			int tt=n%10;
			ans=min(ans,tt);
			n/=10;
			if(ans==1) break;
		}
		cout<<ans<<endl;
	}
	return 0; 
}

B. Z mod X = C

题目

分析

给出a,b,c,找出满足x mod y = a ,y mod z = b ,z mod x = c;的x,y,z。

之前做过类似的题,先做出式子代换,代换为x=k*y+a; y=k*z+b; z=k*x+c;假设z的k为0,其余两个k相同,即可推出x和y的值。

注意:x,y,z的值需要开long long。

代码

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define guanliu ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const ll maxn=2e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);

int main() 
{
	guanliu;
	int t;
	cin>>t;
	while(t--)
	{
		ll a,b,c;
		cin>>a>>b>>c;
		ll x,y,z;
		z=c;
		for(int i=0;i<=1e5;i++)
		{
			y=i*c+b;
			x=i*y+a;;
			if(x%y==a&&y%z==b&&z%x==c) break;
		}
		cout<<x<<" "<<y<<" "<<z<<endl;
	}
	return 0; 
}

C. Column Swapping

题目

分析

只能选择一次两列数,交换他们,使每一行的数都是非递减的。

设需要交换的列的数量为cnt:

当cnt=0,无需交换,可以直接选择交换1 1;
当cnt<=2时,尝试交换两列,并判断交换后,每行的这两列位置的数字是否已与排序后的该位置的数字相等;
当cnt>2时,那么需要交换的次数是大于1的,故无法满足要求;

这题自己手太弱了,赛时一直调不出来,赛后重写了一遍才过。

注意:数组大小2e5,数组存会爆,可以采用vector存。

代码

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define guanliu ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const ll maxn=2e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);
vector<int> v[maxn],vv[maxn];
int n,m;

int check(int i,int j)
{
	for(int k=0;k<n;k++)
	{
		if(v[k][i]!=vv[k][j]||v[k][j]!=vv[k][i]) return 0; 
	}
	return 1;
}

int main() 
{
	guanliu;
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		for(int i=0;i<n;i++)
		{
			v[i].clear();
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				int x;
				cin>>x;
				v[i].pb(x);
			}
			vv[i]=v[i];
			sort(vv[i].begin(),vv[i].end());
		}
		int ansi=-1,ansj=-1;
		int f=1;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(v[i][j]!=vv[i][j])
				{
					if(ansi==-1||ansi==j)
					{
						ansi=j;
					}
					else if(ansj==-1||ansj==j)
					{
						ansj=j;
					}
					else f=0;
				}
			}
		}
		if(!f) cout<<"-1"<<endl;
		else {
			if(ansi==-1&&ansj==-1) cout<<"1 1"<<endl;
			else if(check(ansi,ansj)) cout<<ansi+1<<" "<<ansj+1<<endl;
			else cout<<"-1"<<endl;
		}
	}
	return 0; 
}

D. Traps

题目

分析

需要经过n个陷阱,每个陷阱的伤害是a[i],有k次跳过陷阱的机会,但是一旦跳过一个陷阱之后,这个陷阱之后的每一个陷阱的伤害+1,求通过n个陷阱受到的最小伤害值。

先记录每个陷阱被跳过对总值的影响(不考虑跳过陷阱之间的影响)a[i]-(n-i)。再考虑跳过陷阱之后对其他陷阱的伤害值的影响,跳过m个陷阱,会使伤害减少m(因为跳过一个会让之后的陷阱伤害+1,并且我计算影响时计算了这个值,这个时候跳过,需要减去这个值)。

计算出每个独立跳过的伤害值,并从大到小跳过陷阱,再比较这个值与跳过陷阱个数,考虑继不继续跳过陷阱,一旦这个值小于,即不跳过任何陷阱,即此时伤害最小。

代码

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define guanliu ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const ll maxn=2e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);
ll a[maxn];

bool cmp(ll a,ll b)
{
	return a>b;
}

int main() 
{
	guanliu;
	int t;
	cin>>t;
	while(t--)
	{
		ll sum=0;
		int n,k;
		cin>>n>>k;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			sum+=a[i];
			a[i]=a[i]-(n-i);
		}
		sort(a+1,a+1+n,cmp);
		for(int i=1;i<=k;i++)
		{
			if(a[i]>-i)
			{
				sum-=a[i]+i-1;
			}
			else break;
		}
		cout<<sum<<endl; 
	}
	return 0; 
}

E. MEX vs DIFF

题目

分析

一个数组a,经过最多k次将a[i]换为任意的非负整数,求最小的DIFF-MEX值。

DIFF:数组中不同数的个数。

MEX:数组中没有出现的最小的数。

为使最后差值最小,考虑使MEX值最大,令大于mex的不同数的个数尽量小:muitiset维护一下,让大于mex的数中,数量较少的数优先进行改变操作。

附上本题参考的题解

代码

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define guanliu ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const ll maxn=1e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);
int a[maxn];
int n,k;
map<int,int> mp,dmp;

int main() 
{
	guanliu;
	int t;
	cin>>t;
	while(t--)
	{
		mp.clear();
		cin>>n>>k;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			mp[a[i]]++;
		}
		dmp=mp;
		sort(a+1,a+1+n);
		int mex=0;
		while(mp[mex])
		{
			mex++;
		}
		for(int i=n,j=k;i&&j;i--,j--)
		{
			if(a[i]<mex) break;
			mp[mex]=1;
			mp[a[i]]--;
			while(mp[mex])
			{
				mex++;
			}
		}
		multiset<int> s;
		for(auto i : dmp)
		{
			if(i.first>mex) 
			{
				s.insert(i.second);
			}
		}
		int dif=mex;
		for(auto i : s)
		{
			if(k>=i) k-=i;
			else dif++;
		}
		cout<<dif-mex<<endl;
	}
	return 0; 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值