Codeforces Round 984 (Div. 3) 个人题解(A~G)
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;
}