Codeforces Round #830 (Div. 2)——A、B、C1、D1

A:

题意:

给定一个长度为n的数组,将一个数组变成gcd(a[i], i)的花费是n - i + 1,求出最小花费使得

gcd(a[1]....a[n])=1

方法:要么花费最少,我们肯定是从数组的末端向前进行操作。因为越往后,花费是越小的。我们通过观察可以知道,最大花费就是3。因为我们把最后两个数都通过操作,那么肯定是互质的。问题在于,如何知道操作最后一个数后,是否gcd(数组)=1,或者要操作数组倒数第二个数后,是否gcd(数组)=1。

特判:如果本身gcd(数组)=1,那么花费就是0.如果N=1,花费就是1.

用res判断是否原始数组互质,如果不互质,则res存的是数组中每个数的因子,因为有a[i]=gcd(a[i],i)操作,所以我们只需要用res跟数组下标进行判断就行。因为如果gcd(a[i],i)=1,则说明他们不具有相同的因子,然而res记录了a[i]的因子,所以gcd(res,i)是否互质是等同于gcd(a[i],i)是否互质的。利用这性质,我们就可以判断花费。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];

inline void solve(){
	int n;cin>>n;int res=0;
	for(int i=1;i<=n;i++) cin>>a[i],res=__gcd(res,a[i]);
	if(res==1) cout<<"0\n";
	else if(__gcd(res,n)==1||n==1) cout<<"1\n";
	else if(__gcd(res,n-1)==1) cout<<"2\n";
	else cout<<"3\n";
}

int main(){
	int T;cin>>T;
	while(T--) solve();
}

B: 

 题意:可以选择一个位置使得后面的0变为1,1变为0,问最小的操作次数。

方法:这题需要一些技巧性。因为选择一个位置,那么从这个位置开始到结尾,都得变为对立的数。那么我们用点技巧。因为每选择一个位置,每个数都会变为对应的数。例如:1100,选择位置3,就成为了1111。如果是1011,我们发现,我们只能先选位置2,变为:1100,最后选择位置3,变为1111.那么我们发现,如果相邻的数是相同的,那么在变化后,也是相同的,如果是不同的,变化后也是不同的。所以,我们就选择两个相邻的数,进行操作。具体看代码:

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];

inline void solve(){
	int n;cin>>n;
	string s;cin>>s;
	int ans=0;vector<int>e;
	
	for(int i=0;i<n-1;i++)
		if(s[i]!=s[i+1]) e.push_back(s[i]-'0');
	if(e.size()&&e[0]==0) ans=-1;//以0开头的,第一个位置就不用操作,所以总答案需-1
	cout<<ans+(int)e.size()<<"\n";
}

int main(){
	int T;cin>>T;
	while(T--) solve();
}

 C1:

题意:

给长度为n的数组,求出一段区间的值sum[l, r] - xor[l, r]最大且r - l + 1最小,输出l, r。

方法:异或操作是不进位的加法,但是普通加法是进位的。0显然对答案没有影响,因此长度越长答案一定是越优的,因此这道题的最大值一定是整个数组的和 - 整个数组的XOR,namo我们可以二分找到最短的答案等于最大值的长度。二分长度,双指针扫一遍即可。

 代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int ans,n,k;
int a[N],l,r,ll,rr,s[N],xr[N];

bool check(int len){
	int res=-1<<30,sum=0;
	for(int i=1;i<=n;i++){
		if(i<len){
			sum^=a[i];continue;
		}
		sum^=a[i];sum^=a[i-len];
		if(res<s[i]-s[i-len]-sum){
			res=s[i]-s[i-len]-sum;
			ll=i-len+1,rr=i;
		}
	}
	return res==ans;
}

inline void solve(){
	cin>>n>>k;
	int sum=0;memset(a,0,sizeof(a));
	for(int i=1;i<=n;i++){
		cin>>a[i];s[i]=s[i-1]+a[i];
		sum^=a[i];
	}
	int x,y;cin>>x>>y;
	ans=s[n]-sum;
	int l=1,r=n;
	while(l<r){
		int mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	check(l);
	cout<<ll<<" "<<rr<<"\n";
}

signed main(){
	int T;cin>>T;
	while(T--) solve();
}

 D1:

 题意:

初始的set里只有元素0,若干个操作可以往set里添加元素但是不会减少元素。查询操作是求出第一个不出现在set里的k的倍数。

方法:在放入每个数的时候,对其标记一下,如果查询值的倍数不在容器内,就输出,否则再增大倍数,再判断。

代码:

#include<bits/stdc++.h>
#define int long long 
using namespace std;
set<int>se;
map<int,int>mp;// first:k  second:k-mex

inline void solve(){
	int q;cin>>q;
	char op;int x;
	while(q--){
		cin>>op>>x;
		if(op=='+') se.insert(x);
		else{
			int cur;
			if(mp.count(x)) cur=mp[x];//如果在map中,数x存在,就让cur= k-mex
			else cur=x;//否则就等于这个数
			while(se.count(cur)) cur+=x;//如果在容器中存在,就在x上加一个倍数
			mp[x]=cur;//此时再在map中标记一次map[x]对应的k-mex
			cout<<cur<<"\n";
		}
	}
}

signed main(){
	solve();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值