CodeForces Round #653 div3

A. Required Remainder
数学思维题
题意:求0~n内对x取模以后为y的最大数k为多少,就是求n以内最多能够包含几个x(设有m个),即n>=mx+y,移项可得m<=(n-y)/x,则易构造所求最大值k为:k=mx+y=x*((n-y)/x)+y,则ac代码如下:

#include<iostream>

using namespace std;

int main()
{
	int x,y,n,t;
	cin>>t;
	while(t--){
		cin>>x>>y>>n;
		cout<<x*((n-y)/x)+y<<endl;
	}	
	return 0;
}

B. Multiply by 2, divide by 6
数学思维题
题意:给出一个数n,求通过几次除6,乘2的操作可以得到1,输出操作数,如果得不到1,就输出-1

#include<iostream>
#include<algorithm>

using namespace std;

int main()
{
	int n,t;
	cin>>t;
	while(t--){
		cin>>n;
		int cnt=0;
		while(n%3==0){
			if(n%6==0) n/=6;
			else n*=2;
			cnt++;
		} 
		if(n==1)cout<<cnt<<endl;
		else cout<<"-1"<<endl;
	}
	return 0;
}

C. Move Brackets
简单栈应用

#include<iostream>
#include<stack>

using namespace std;

int main()
{
	int n,t;
	cin>>t;
	while(t--){
		stack<char> st;
		cin>>n;
		char s;
		for(int i=0;i<n;i++){//先把给出序列中的(全部和)匹配完,剩下栈中都是(,其数量即最小移动步数 
			cin>>s;
			if(s=='('){ 
				st.push(s);
			}else if(!st.empty()&&s==')'){
				st.pop();
			}
		}
		cout<<st.size()<<endl;
	}
	return 0;
}

D. Zero Remainder Array
题意:给出一个数组a,开始有x=0,x可以进行自增,次数不限,对数组的每个元素,最多只能进行一次ai+x操作,问使得数组每个元素都能整除k的最小操作数
参考博文地址
解题思路:对数组所有元素求出其达到整除k时所需要的步数为k-a[i]%k,当同余元素有多个时,会进行循环,从同余元素中的最小值开始,变成k的倍数,比如k为3时数组中有两个1,两个1到达3所需步数都为2,先让第一个1到达3,此时第二个1则应达到3的倍数6,据此推演,出现多个同余元素(假设有maxn个)时则除同余元素中最小值以外的元素所需步数应是加上(maxn-1)*k,而最小值所需步数为其本身+1(x是从0开始自增的,这里需要加1),将次数最多的最大同余数组所需操作数看作最后所需最小操作数,而前面更小的元素看成x达到同余数组第一个最小值时所需步数的子步(所以这里用了map数组进行排序)
注:我开始用的int,wa在了test5,后来改成longlong就ac了

#include<iostream>
#include<map>

using namespace std;

typedef long long ll;

int main()
{
	ll n,k,t,x;
	cin>>t;
	while(t--){
		map<ll,ll> mp;//以到达k的倍数所需步数为关键字,同余元素个数为值 
		mp.clear();
		cin>>n>>k;
		ll maxn=0,maxs=0;//maxn存储最大次数,maxs存储同余元素最大次数到达nk所需最小步数 
		for(int i=1;i<=n;i++){
			cin>>x;
			x%=k;
			if(x==0)continue;//忽略已经能够整除k的元素的情况 
			x=k-x;
			mp[x]++;
			if(mp[x]>maxn){maxs=x;maxn=mp[x];}//更新
			else if(maxn==mp[x]&&x>maxs)maxs=x; //次数相同时取所需步数大的,使它尽可能经过更多的中间子步 
		}
		if(maxs==0)cout<<"0"<<endl;
		else cout<<maxs+1+(maxn-1)*k<<endl;
	}
	return 0;	
}

E1. Reading Books (easy version)
解题思路:使得ab同时为1加上a为1或b为1时的时间总和T最小即所求答案
ac代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=2*1e5+3;
int n,t[maxn],ta[maxn],tb[maxn];

int main()
{
	int k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){t[i]=ta[i]=tb[i]=0;}
	int tt,a,b,T=0,p1=0,p2=0,p3=0;
	for(int i=0;i<n;i++){
		scanf("%d%d%d",&tt,&a,&b);
		if(a&&b){t[p1++]=tt;}
		else if(a){ta[p2++]=tt;}
		else if(b){tb[p3++]=tt;}
	}//将ab同时为1的time存入t数组,只有a为1时存入ta,只有b为1时存入tb,方便分开处理并排序 
	if(p1+p2<k||p1+p3<k){printf("-1\n");return 0;}//如果两个人中有一个达不到k就直接退出打印-1 
	sort(t,t+p1);
	sort(ta,ta+p2);
	sort(tb,tb+p3);
	tt=a=b=0;
	for(int i=0;i<k;i++){
		if(tt<p1&&a<p2&&b<p3){
			if(t[tt]<ta[a]+tb[b])T+=t[tt++];
			else T+=ta[a++]+tb[b++];
		}else if(tt==p1){
			T+=ta[a++]+tb[b++];//没有ab同时为1时的time就直接加上ab单独为1时数值 
		}else{T+=t[tt++];}//ab单独为1的情况处理完了还不够k继续处理同时为1的情况 
	}
	printf("%d\n",T);
	return 0;	
}

参考博文
这道题我还有疑问,开始我的思路是直接给t数组排序,让a和b数组跟着t数组动,以免ab和t对应错误,我用了归并排序,过程中让ab一起动,后来甚至用上了冒泡排序,但是始终不行,ab数组和t数组老是对应错误导致结果错误,后来看了上面这位博主的文章改用三个数组来存,的确是避免了我一个数组存时间来排序时ab数组的对应问题,但是按道理来说我开始这个思路应该可以的呀,怎么会错呢?请各位大佬指教,谢谢了
错误代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=2*1e5+3;
int n,a[maxn],b[maxn],t[maxn],ta[maxn];
int cnt=0;
//处理方法1 归并排序 
void merge(int l,int mid,int r)
{
	memset(ta,0,sizeof(ta));
	int p1=l,p2=mid+1,pos=l;
	while(p1<=mid&&p2<=r){
		if(t[p1]<=t[p2])ta[pos++]=t[p1++];
		else{
		swap(a[p1],a[p2]);swap(b[p1],b[p2]);
		ta[pos++]=t[p2++];
		}
	}//p1=2,p2=5的时候a数组元素交换不成功,怎么回事? 
	while(p1<=mid)ta[pos++]=t[p1++];
	while(p2<=r)ta[pos++]=t[p2++];
	for(int i=l;i<=r;i++)t[i]=ta[i];
}

void merge_sort(int l,int r)
{
	if(l<r){
		int mid=(l+r)/2;
		merge_sort(l,mid);
		merge_sort(mid+1,r);
		merge(l,mid,r);
	} 
}

/*void Bubble_sort()  处理方法2 冒泡排序 
{
	for(int i=1;i<=n-1;i++){
		for(int j=i+1;j<=n;j++){
			if(t[i]>t[j]){
				swap(t[i],t[j]);
				swap(a[i],a[j]);
				swap(b[i],b[j]);
			}
		}
	}	
}*/

int main()
{
	int k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){t[i]=a[i]=b[i]=0;}
	int num1=0,num2=0,T=0,tk=0;
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&t[i],&a[i],&b[i]);
		if(a[i])num1++;
		if(b[i])num2++;
	}
	if(num1<k||num2<k){printf("-1\n");return 0;}
	for(int i=1;i<=n;i++){
		if(tk==k)break;
		if(a[i]==1&&b[i]==1){T+=t[i];tk++;a[i]=0,b[i]=0;}
	}
	if(tk<k){
		//sort(t+1,t+n+1);不能直接对t数组排序,不然ab数组和t数组对应不上 
		merge_sort(1,n);
		//Bubble_sort();
		num1=num2=0;
		for(int i=1;i<=n;i++){
			if(num1+tk==k&&num2+tk==k)break;
			if(num1+tk<k&&a[i]==1){T+=t[i];++num1;}
			if(num2+tk<k&&b[i]==1){T+=t[i];++num2;}
		}
	}
	printf("%d\n",T);
	return 0;	
}

E2. Reading Books (hard version)
题意:这道题算是上面那道题的加强版,给出n本书,从中选m本使得同为1或ab其中一个为1的情况加起来总和尽可能小
解题思路:如果说给出的n本书a和b其中一个的1的个数达不到k个,那么不管怎么选m本书肯定都不符合要求,因此这个时候直接退出打印-1,都能选到k本书时先按上题思路选出尽可能小的k本书时间总和,然后用一个tm存储所有书时间,已经被用过的过程中置0,在选完k本还不够m本的情况下继续从tm中从小开始选使时间总和最小,问题是怎么让

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值