Codeforces Round 984 (Div. 3) 个人题解(A~G)

Codeforces Round 984 (Div. 3) 个人题解

Codeforces Round 984 (Div. 3)

Problem - A - Codeforces

解题思路

  • n很小,直接枚举即可
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
int a[100];
void solve(){
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=2;i<=n;i++){
		int t=abs(a[i]-a[i-1]);
		if(t!=5 && t!=7){
			cout<<"NO"<<endl;
			return;
		}
	}
	cout<<"YES"<<endl;
}
int main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

Problem - B - Codeforces

解题思路

  • 统计每种成本的瓶子的价值总和,取前k大即可
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
int c[N];
void solve(){
	int n,k;cin>>n>>k;
	map<int,int> mp;
	for(int i=1;i<=k;i++){
		int b,c;cin>>b>>c;
		mp[b]+=c;
	}
	int tot=0;
	for(auto [x,v]:mp){
		c[++tot]=v;
	}
	sort(c+1,c+tot+1);
	int cnt=0;
	int ans=0;
	for(int i=tot;i>=1;i--){
		ans+=c[i];
		cnt++;
		if(cnt>=n) break;
	}
	cout<<ans<<endl;
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

Problem - C - Codeforces

解题思路

  • 改变一个位置,只会改变包含该位置的子串,暴力枚举即可
  • 这里的维护方式是先记录原字符串的1100个数tot,然后记录指定位置改变前的1100个数cnt1,然后记录改变后的1100个数cnt2,这样的话得到的新串的1100个数即为tot-cnt1+cnt2
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
void solve(){
	string s;cin>>s;
	int n=s.size();
	s=" "+s;
	int tot=0;
	for(int i=1;i<=n-3;i++){
		if(s[i]=='1' && s[i+1]=='1' && s[i+2]=='0' && s[i+3]=='0'){
			tot++;
		}
	}
	int q;cin>>q;
	while(q--){
		int x;
		char y;
		cin>>x>>y;
		if(n<4){
			cout<<"NO"<<endl;
			continue;
		}
		int cnt1=0;
		for(int i=x-3;i<=x;i++){
			if(i<1 || i+3>n) continue;
			if(s[i]=='1' && s[i+1]=='1' && s[i+2]=='0' && s[i+3]=='0'){
				cnt1++;
			}
		}
		s[x]=y;
		int cnt2=0;
		for(int i=x-3;i<=x;i++){
			if(i<1 || i+3>n) continue;
			if(s[i]=='1' && s[i+1]=='1' && s[i+2]=='0' && s[i+3]=='0'){
				cnt2++;
			}
		}
		tot=tot+cnt2-cnt1;
		if(tot) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

Problem - D - Codeforces

解题思路

  • 题目从外层依次向内,考虑递归解决
  • 我们可以每次递归的找每一层的左上角顶点,以及该圈的底部d和右侧r
  • 这样的话将每一圈按顺时针存入字符串判断即可
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N=1010;
char g[N][N];
int n,m,ans=0;
void dfs(int d,int r,int x,int y){
	if(d<=n/2 || r<=m/2) return;
	string tmp; 
	for(int j=y;j<=r;j++) tmp+=g[x][j];
	for(int i=x+1;i<=d;i++) tmp+=g[i][r];
	for(int j=r-1;j>=y;j--) tmp+=g[d][j];
	for(int i=d-1;i>=x+1;i--) tmp+=g[i][y];
	int len=tmp.size();
	tmp+=tmp;
	int len2=tmp.size();
	tmp=" "+tmp;
	for(int i=1;i<=len;i++){
		if(i+3>len2) continue;
		if(tmp[i]=='1' && tmp[i+1]=='5' && tmp[i+2]=='4' && tmp[i+3]=='3'){
			ans++;
		}
	}
	dfs(d-1,r-1,x+1,y+1);
}
void solve(){
	ans=0;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>g[i][j];
		}
	}
	dfs(n,m,1,1);
	cout<<ans<<endl;
}
int main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

Problem - E - Codeforces

解题思路

  • b数组由a数组连续的或产生,所以b数组单调不减
  • 为了满足m个要求,我们可以设置边界l,r每次二分出满足当前边界的tl,tr,与l,r分别取max与min
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
void solve(){
	int n,k,q;cin>>n>>k>>q;
	vector<vector<int>> v(n+5);
	for(int i=1;i<=n;i++) v[i].resize(k+5);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=k;j++){
			cin>>v[i][j];
		}
	}
	vector<vector<int>> pre(k+5);
	for(int i=1;i<=k;i++) pre[i].resize(n+5);
	for(int j=1;j<=k;j++){
		for(int i=1;i<=n;i++){
			if(i!=1) v[i][j]|=v[i-1][j];
			pre[j][i]=v[i][j];
		}
	}
	// for(int i=1;i<=k;i++){
		// for(int j=1;j<=n;j++) cout<<pre[i][j]<<" ";
		// cout<<endl;
	// }
	while(q--){
		int m;cin>>m;
		int l=1,r=n;
		for(int i=1;i<=m;i++){
			int x,y;char op;
			cin>>x>>op>>y;
			if(op=='<'){
				int idx=lower_bound(pre[x].begin()+1,pre[x].begin()+n+1,y)-pre[x].begin();
				idx--;
				r=min(idx,r);
			}
			else if(op=='>'){
				int idx=upper_bound(pre[x].begin()+1,pre[x].begin()+n+1,y)-pre[x].begin();
				l=max(idx,l);
			}
		}
		if(l>r) cout<<-1<<endl;
		else cout<<l<<endl;
	}
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
	while(T--) solve();
	return 0;
}

Problem - F - Codeforces

解题思路

  • 一道考察异或性质的题目,f[l,r]表示l xor l+1 xor ... xor r

    • 异或可以用类似前缀和的方式维护,f[l,r]=f[0,l-1] xor f[0,r]
    • 当r%4==0时,f[0,r]=n
    • 当r%4==1时,f[0,r]=1
    • 当r%4==2时,f[0,r]=n+1
    • 当r%4==3时,f[0,r]=0
    • xor的逆运算仍是xor,如a xor b = c ,则a = c xor b
  • 我们令f[l,r]表示区间[l,r]所有数的xor和,令fa[l,r]表示区间[l,r]中% \(2^{i}\) ≠ k的数字的xor和,令fb[l,r]表示区间[l,r]中% \(2^{i}\) = k的数字的xor和

  • 我们可以推出fa[l,r]=f[l,r]fb[l,r]=f[0,r]f[0,l-1]fb[0,r]f[0,l-1]

  • f[0,x]很好计算,考虑怎么计算fb[0,r]

  • 观察一下我们发现% \(2^{i}\) =k 实际上就是对于一个数二进制后部需要等于k,并且前面的某个前缀也是从0开始递增的

  • 例如k=(101)2,i=3,(1000)2,x=110101,实际上前缀就是从0到110,然后用上述处理前缀的方法即可

  • 至于k的部分我们只需判断有多少个k异或,奇数则为k,偶数则为0

  • 这里需要注意判断一下这个前缀的上界,具体细节可以看代码实现

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int l,r,id,k;
int calc(int x){
	if(x%4==0) return x;
	if(x%4==1) return 1;
	if(x%4==2) return x+1;
	if(x%4==3) return 0;
}
int calc2(int x){
	int num=0;
	if(x<k) return 0;
	int t=(x>>id)<<id|k;
//	cout<<t<<endl;
	if(t<=x) num=x>>id;
	else num=(x>>id)-1;
//	cout<<num<<endl;
	int res=calc(num)<<id;
	if((num+1)%2) res|=k; 
	return res;
}
void solve(){
	cin>>l>>r>>id>>k;
	int ans1=calc(l-1);
	int ans2=calc(r);
//	cout<<ans1<<" "<<ans2<<endl;
	if(r<k){
		int ans=ans1^ans2;
		cout<<ans<<endl;
		return;
	}
	int ans3=calc2(l-1);
	int ans4=calc2(r);
//	cout<<ans3<<" "<<ans4<<endl;
	int ans=ans1^ans2^ans3^ans4;
	cout<<ans<<endl;		
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

Problem - G - Codeforces

解题思路

  • 不妨设a<b<c

  • a ^ b ^ c > 0

    • 假设a ^ b ^ c == t,我们可以二分check(1,n),询问(1,mid)结果等于t则r=mid-1,否则l=mid+1
    • 这样的话我们就可以找到c,接着check(1,c-1),这样就能找到b
    • 利用xor逆运算仍是xor的性质,a=bct
  • a ^ b ^ c == 0

    • 因为三者异或和为0,容易发现二进制最高位一定为两个1,1个0,所以询问的时候只需要询问\(2^{i}\),这样必能找到a或者找到a,b,找到a,b的原因是b有可能等于\(2^{i}\),这里怎么判断呢,很简单,因为a^b==c,所以秩序判断询问是否等于c就可以知道找到了a还是c,之后秩序按照上面的方法check即可
#include<bits/stdc++.h>
#define int long long
using namespace std;
int ask(int l,int r){
	cout<<"xor "<<l<<" "<<r<<endl;
	int x;cin>>x;
	return x;
}
int check(int L,int R){
	int t=ask(L,R);
	int l=L,r=R;
	int ans=R;
	while(l<=r){
		int mid=(l+r)>>1;
		int x=ask(L,mid);
		if(x==t){
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	return ans;
}
void solve(){
	int n;cin>>n;
	int t=ask(1,n);
	if(t>0){
		int c=check(1,n);
		int b=check(1,c-1);
		int a=b^c^t;
		cout<<"ans "<<a<<" "<<b<<" "<<c<<endl;
		return;
	}
	else{
		for(int i=1;i>0;i<<=1){
			int x=ask(1,i);
			if(x==0) continue;
			int a=0,b=0,c=0;
			if(x>i){
				c=x;
				b=check(1,c-1);
				a=b^c^t;
			}
			else{
				a=x;
				c=check(a+1,n);
				b=a^c^t;
			}
			cout<<"ans "<<a<<" "<<b<<" "<<c<<endl;
			return;
		}
	}
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

posted @ 2024-11-04 09:52  Persona_owl  阅读(44)  评论(4编辑  收藏  举报