Codeforces Round 984 (Div. 3)
Codeforces Round 984 (Div. 3) 总结
https://codeforces.com/contest/2036
A
按题意模拟判断一下即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n;
int a[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=2;i<=n;i++)
{
if(abs(a[i]-a[i-1])!=5&&abs(a[i]-a[i-1])!=7)
{
cout<<"No\n";
return ;
}
}
cout<<"Yes\n";
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--) solve();
return 0;
}
B
统计每种品牌的总价值,取前 \(n\) 个最大值。数据较小,直接用数组装,排序后取前 \(n\) 大。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,k;
int a[N];
void solve()
{
cin>>n>>k;
for(int i=1;i<=k;i++)
{
int b,c;
cin>>b>>c;
a[b]+=c;
}
sort(a+1,a+k+1);
int ans=0;
for(int i=k;i>=max(0,k-n+1);i--) ans+=a[i];
cout<<ans<<'\n';
for(int i=1;i<=k;i++) a[i]=0;
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--) solve();
return 0;
}
C
先统计有多少个 1100
。
可以知道,修改过后能影响的范围很小,判断一下改变前后是否是 1100
。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=2e5+5;
string s;
int n,q;
bool check(int i)
{
if(i<1||i+3>n) return 0;
if(s[i]=='1'&&s[i+1]=='1'&&s[i+2]=='0'&&s[i+3]=='0') return 1;
return 0;
}
void solve()
{
cin>>s>>q;
n=s.size();
int cnt=0;
s="0"+s;
for(int i=1;i<=n-3;i++)
{
if(check(i)) cnt++;
}
while(q--)
{
int k;
char x;
cin>>k>>x;
if(s[k]!=x)
{
if(x=='1')
{
if(check(k-3)||check(k-2)) cnt--;
s[k]=x;
if(check(k)||check(k-1)) cnt++;
}
else
{
if(check(k)||check(k-1)) cnt--;
s[k]=x;
if(check(k-3)||check(k-2)) cnt++;
}
}
if(cnt) cout<<"Yes\n";
else cout<<"No\n";
}
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--) solve();
return 0;
}
D
将每一层的数据按顺时针提出来,因为只要判断 \(4\) 位,所以在最后加上前三个数,断环成链。统计有多少个 1543
。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=1005,M=5005;
int n,m;
string g[N];
char a[M];
bool check(int i)
{
if(a[i]=='1'&&a[i+1]=='5'&&a[i+2]=='4'&&a[i+3]=='3') return 1;
return 0;
}
void solve()
{
cin>>n>>m;
int cnt=n*m;
for(int i=0;i<n;i++) cin>>g[i];
int s=0,ans=0;
while(cnt)
{
int tot=0;
int x=s,y=s-1;
while(y+1<m-s) a[++tot]=g[x][++y],cnt--;
while(x+1<n-s) a[++tot]=g[++x][y],cnt--;
while(y-1>=s) a[++tot]=g[x][--y],cnt--;
while(x-1>s) a[++tot]=g[--x][y],cnt--;
a[++tot]=a[1],a[++tot]=a[2],a[++tot]=a[3];
for(int i=1;i<=tot-3;i++) if(check(i)) ans++;
s++;
}
cout<<ans<<'\n';
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--) solve();
return 0;
}
E
先预处理 \(b_{i,j}\) 出来。
按位或的大小单调不减,可以二分确定范围,要注意 \(j\) 要作为第一维,便于二分查找。要注意一下边界问题,tourist 都吃罚时了 qwq。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,m,q;
vector<vector<int> >g;
void solve()
{
cin>>n>>m>>q;
g.resize(m);
for(int j=0;j<m;j++) g[j].resize(n);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>g[j][i];
for(int j=0;j<m;j++)
for(int i=1;i<n;i++)
g[j][i]|=g[j][i-1];
while(q--)
{
int l=1,r=n,st=0;
int m;
int x,y;
char op;
cin>>m;
while(m--)
{
cin>>x>>op>>y;
x--;
if(op=='<')
{
int id=lower_bound(g[x].begin(),g[x].end(),y)-g[x].begin();
if(id<1) st=1;
else r=min(r,id);
}
else
{
int id=upper_bound(g[x].begin(),g[x].end(),y)-g[x].begin()+1;
if(id>n) st=1;
else l=max(l,id);
}
}
if(l<=r&&st==0) cout<<l<<'\n';
else cout<<-1<<'\n';
}
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
F
设 \(f(l, r) = l \oplus (l+1) \oplus \dots \oplus r\)。\(\oplus\) 表示按位异或。
神奇的规律:
可以打表找规律。或者利用连续四个自然数异或和为 \(0\) 来推导。
这篇博客有详细证明:https://www.cnblogs.com/Mychael/p/8633365.html
因为 \(a \oplus a=0\),所以 \(f(l,r)=f(0,r) \oplus f(0,l-1)\)。
直接求满足 \(x \not\equiv k \mod 2^i\) 的 \(x\) 不好求,但是可以求 \(x \equiv k \mod 2^i\),\(x\) 是 \([l,r]\) 中 \(k\) 的超集,后 \(i\) 位与 \(k\) 相同。设 \(x=k+j \times 2^i\),\(j\) 的范围为 \(\LARGE[\large\left\lceil \frac{l - k}{2^i} \right\rceil , \left\lfloor \frac{r - k}{2^i} \right\rfloor\LARGE]\)。
将 \(x\) 拆成两部分,二进制下后面 \(i\) 位都一样,所以要看 \(x\) 的范围大小是奇数还是偶数,是奇数的话后 \(i\) 位异或和就是 \(k\)。其他位就是算 \(j\) 的异或和,最后乘上 \(2^i\) 就行。\(j\) 的异或和也是那样算的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=1;
ll l,r,i,k;
ll pre(ll x)
{
if(x<=0) return 0;
if(x%4==1) return 1;
if(x%4==2) return x+1;
if(x%4==3) return 0;
return x;
}
void solve()
{
cin>>l>>r>>i>>k;
ll ans=pre(r)^pre(l-1);
r=(r-k)>>i,l=((l-k+(1ll<<i)-1)>>i);
if(l<0) l=0;
if(r-l+1&1) ans^=k;
ans^=(pre(r)^pre(l-1))<<i;
cout<<ans<<'\n';
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--) solve();
return 0;
}