Codeforces Round 984 (Div. 3)题解记录(A~G)
比赛链接:https://codeforces.com/contest/2036
A. Quintomania
思路:数据范围小+题目清晰,题目要求左右两个数之差绝对值不等于\(5\)或这不等于\(7\),直接暴力即可,应该不会有人不知到内置函数\(abs\)吧
#include<iostream>
#include<queue>
#include<map>
#include<set>A~F
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n;
cin>>n;
ll pd=0;
ll o;
for(ll i=1;i<=n;i++)
{
ll x;
cin>>x;
if(i>=2)
{
if(abs(o-x)==5||abs(o-x)==7)
{
o=x;
continue;
}
pd=1;
}
o=x;
}
if(pd)
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
}
}
B. Startup
思路:一开始看成选(总瓶子大于\(k\))\(k\)个瓶子放在\(n\)个货架上,然后货架上的牌子只能是同一种,感觉很难。
随后发现看错了,是总共有\(k\)个瓶子,然我放在\(n\)个货架上,且品牌得一样,于是直接贪心的把所有品牌对应的值进行累积,
然后进行排序,从大到小选取前\(min(n,牌子种类)\)个即可,本人为了方便直接用了优先对列
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n,k;
cin>>n>>k;
map<ll,ll>mp;
set<ll>q;
priority_queue<ll>f;
for(ll i=1;i<=k;i++)
{
ll x,y;
cin>>x>>y;
mp[x]+=y;
q.insert(x);
}
for(auto j:q)
{
f.push(mp[j]);
}
ll ans=0;
while(!f.empty())
{
ans+=f.top();
f.pop();
n--;
if(n==0)
break;
}
cout<<ans<<endl;
}
}
C. Anya and 1100
思路:对于一个字符串有\(q\)次修改,问每次修改后是否存在\(1100\)字串
不妨想想,每次修改一个位置,最多会影响\(4\)个位置的可能,所以直接先暴力统计一开始的所有\(1100\)子串,然后每次修改进行区间\(1100\)变化统计
然后再修改原本的\(1100\)个数就可以了
赛事犯了个低级错误,一开始统计\(1100\)直接\(4\)个\(4\)个查了。···
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
string f;
cin>>f;
ll n=f.size();
ll q;
cin>>q;
ll ans=0;
f='0'+f;
for(ll i=1;i<=n-3;i++)
{
if(f[i]=='1'&&f[i+1]=='1'&&f[i+2]=='0'&&f[i+3]=='0')
ans++;
}
while(q--)
{
ll x;
char y;
cin>>x>>y;
if(n<4)
{
cout<<"NO"<<endl;
continue;
}
else
{
ll cnt=0;
//cout<<n<<endl;
for(ll i=x-3;i<=x;i++)
{
if(i>=1&&i+3<=n)
{
if(f[i]=='1'&&f[i+1]=='1'&&f[i+2]=='0'&&f[i+3]=='0')
cnt++;
}
}
f[x]=y;
ll uo=0;
for(ll i=x-3;i<=x;i++)
{
if(i>=1&&i+3<=n)
{
if(f[i]=='1'&&f[i+1]=='1'&&f[i+2]=='0'&&f[i+3]=='0')
uo++;
}
}
//cout<<cnt<<endl;
uo-=cnt;
ans+=uo;
if(ans>0)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
}
}
D. I Love 1543
思路:其实就是模拟下字符串有没有\(1543\),如何模拟?
首先外围走一圈顺时针是很有格式规定的,于是考虑递归写,然后终止条件可以画画,是目前最大行小于等于\(n/2\)或者目前最大列小于等于\(m/2\)
,然后每次缩一次上边界和下边界就可以了,统计的话为了方便直接重新进行字符串加和,然后再倍增一下,枚举\(0到size()/2-1\)最为第一个字符就可以了,注意防止越界哦
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
string f[4000];
ll n,m;
ll ans=0;
void ck(ll x,ll y,ll s,ll p)
{
if(x<=n/2||y<=m/2)
return ;
string u="";
for(ll j=p;j<=y;j++)
{
u+=f[s][j];
}
for(ll j=s+1;j<=x;j++)
{
u+=f[j][y];
}
for(ll j=y-1;j>=p;j--)
{
u+=f[x][j];
}
for(ll i=x-1;i>=s+1;i--)
{
u+=f[i][p];
}
//cout<<u<<endl;
ll k=u.size()-1;
u+=u;
for(ll i=0;i<=k;i++)
{
if(i+3<=(ll)u.size()-1&&u[i]=='1'&&u[i+1]=='5'&&u[i+2]=='4'&&u[i+3]=='3')
{
ans++;
}
}
//cout<<ans<<endl;
ck(x-1,y-1,s+1,p+1);
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
//ll n,m;
cin>>n>>m;
for(ll i=1;i<=n;i++)
{
cin>>f[i];
f[i]='0'+f[i];
}
ans=0;
ck(n,m,1,1);
cout<<ans<<endl;
}
}
E. Reverse the Rivers
思路:\(n*k<=10^5\),所以在\(main\)函数内定义二维数组,然后先按照题目要求进行处理或之和(两个数之或一定不变或者增加,所以或之和是不递减的,具有单调性),然后再用一个数组以列为第一维行为第二维统计每行对应的数,然后有\(q\)次询问,但是注意\(m<=10^5\),所以其实也就最多有\(m\)个约束。因为题目要求找到合理的最小序号,所以要用\(l,r\)双指针进行区间维护,对于\(<\),可以用\(lower_bound\)找到第一个大于等于\(y\)的行\(c\),然后\(c--\),取\(r=min(r,c)\),对于\(>\),可以用\(upper_bound\)直接找到对应的行\(c\),然后取\(l=max(l,c)\)即可,如果\(l>r\),输出\(-1\),否则输出\(l\)
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
ll t;
t=1;
while(t--)
{
ll n,k,q;
cin>>n>>k>>q;
ll a[n+5][k+5];
for(ll i=0;i<=n;i++)
{
for(ll j=0;j<=k;j++)
{
a[i][j]=0;
}
}
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=k;j++)
{
cin>>a[i][j];
}
}
//cout<<a[0][1]<<endl;
ll b[k+5][n+5]={0};
for(ll j=1;j<=k;j++)
{
for(ll i=1;i<=n;i++)
{
a[i][j]=(a[i][j]|a[i-1][j]);
b[j][i]=a[i][j];
//cout<<a[i][j]<<endl;
}
}
//cout<<b[1][2]<<endl;
while(q--)
{
ll m;
cin>>m;
ll l=1,r=n;
for(ll i=1;i<=m;i++)
{
ll x,y;
char f;
cin>>x>>f>>y;
if(f=='<')
{
ll u=lower_bound(b[x]+1,b[x]+1+n,y)-b[x];
u--;
r=min(r,u);
}
else
{
ll u=upper_bound(b[x]+1,b[x]+1+n,y)-b[x];
l=max(l,u);
}
}
if(l>r)
{
cout<<-1<<endl;
}
else
cout<<l<<endl;
}
}
}
F. XORificator 3000
思路:赛时没考虑r<k时直接输出答案,一直WA2
其实对于一个从1开始的连续区间的异或和,其答案是有规律的
规律如下:
当\(n%4==0\):
\(f(1,n)=n\)
当\(n%4==1\):
\(f(1,n)=1\)
当\(n%4==2\):
\(f(1,n)=n+1\)
当\(n%4==3\):
\(f(1,n)=0\)
显然对于\(f(l,r)\)有\(f(l,r)=f(1,r)^f(1,l-1)\)
随后如何处理不合理答案
其实容易发现对于\(2^i\)乘连续数的答案的异或之和会等于连续的数的异或之和乘以\(2^i\)
所以解决了\(2^i\)的问题然后是对于\(k\),他其实一直在异或自己,如果异或了自己偶数次,则为\(0\),否则为本身,这个的次数奇偶性等于区间\(2^i*b+k\),\(b\)的可能个数的奇偶性
最后处理好是否异或\(k\)就行了,注意特判情况\(r<k\)哦
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll __int64
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll ck(ll r)
{
if(r%4==0)
{
return r;
}
else if(r%4==1)
{
return 1;
}
else if(r%4==2)
{
return r+1;
}
else
{
return 0;
}
}
int main()
{
ll t;
cin>>t;
while(t--)
{
ll l,r,f,k;
cin>>l>>r>>f>>k;
ll ans=0;
ans=(ck(r)^ck(l-1));
if(r<k)
{
cout<<ans<<endl;
continue;
}
//cout<<ans<<endl;
ll u=1<<f;
ll l1=(l-k)/u+((l-k)%u>0);
ll r1=(r-k)/u;
ll op;
op=ck(r1)^ck(l1-1);
op*=u;
ans^=op;
if((r1-l1+1)%2==0)
cout<<ans<<endl;
else
{
cout<<(ans^k)<<endl;
}
}
}
G. Library of Magic
思路:虽然上个思路错了,但是这次总算对了,因为问的次数不能超过150次
所以分类讨论
如果\(query(1,n)==0\):
代表着,存在三个是异或和为0,由于这个性质可以得出如果把1-n分成2得次幂的区间,区间询问大于0的个数一定会大于等于2
所以当个数等于2时,可以根据2进制最高位数相同异或为0,比左区间小得出一个区间是否存在两个数,然后另一个区间的询问数值就是答案之一,
然后二分还不知道答案的区间,可得出第二个答案,然后用区间询问异或这个答案就可得出第三个答案
当个数为3时,就二分出第一个答案,然后扩大下询问区间再得到一个异或和,用它与第一个答案异或得出第二个,以此类推得第三个
如果\(query(1,n)!=0\):
这个时候直接二分两次就可以了,直接得出两个答案,然后总区间异或去异或前两个答案,得出第三个答案
交互题确实写得比较难受
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}//对于三个数异或和为0,只可能在最高二进制数不同时才出现
ll q(ll x,ll y)
{
cout<<"xor"<<" "<<x<<" "<<y<<endl;
cout.flush();
cin>>x;
return x;
}
//ll a[2500000];
bool cmp(pair<ll,ll> x,pair<ll,ll> y)
{
return x.first<y.first;
}
pair<ll,ll>a[50];
ll ef(ll l,ll r)
{
while(l<r)
{
ll mid=(l+r)>>1;
if(q(l,mid))
{
r=mid;
}
else
l=mid+1;
}
return r;
}
vector<ll>ans;
void solve()
{
ans.clear();
//map<ll,ll>mp;
ll n;
cin>>n;
set<ll>f;
ll o=0;
ll cnt=0;
ll d=q(1,n);
if(d==0)
{
for(ll i=0;i<=63;i++)
{
if((1ll<<i)>n)break;
//cout<<(1ll<<i)<<endl;
if(q(1ll<<i,min(n,((1ll<<(i+1))-1))))
{
cnt++;
a[cnt]={1ll<<i,min(n,((1ll<<(i+1))-1))};
}
}
if(cnt==3)
{
//cout<<cnt<<endl;
// sort(a+1,a+1+3,cmp);
ll u=ef(a[1].first,a[1].second);
d^=u;
ans.push_back(u);
ll j=q(a[1].first,a[2].second);
j^=u;
ans.push_back(j);
d^=j;
ans.push_back(d);
}
else if(cnt==2)
{
ll op=0;
sort(a+1,a+1+2,cmp);
ll u=q(a[1].first,a[1].second);
if(u<a[1].first)
{
ll j=ef(a[1].first,a[1].second);
ans.push_back(j);
ans.push_back(j^u);
d^=u;
ans.push_back(d);
}
else
{
ans.push_back(u);
d^=u;
ll j=ef(a[2].first,a[2].second);
ans.push_back(j);
d^=j;
ans.push_back(d);
}
}
else
{
//ll op=0;
ll k=ef(a[1].first,a[1].second);
d^=k;
ans.push_back(k);
k=ef(k+1,a[1].second);
d^=k;
ans.push_back(k);
ans.push_back(d);
}
}
else
{
ll k=ef(1,n);
ans.push_back(k);
d^=k;
k=ef(k+1,n);
ans.push_back(k);
d^=k;
ans.push_back(d);
}
//sort(ans.begin()),ans.end());
cout<<"ans";
for(auto j:ans)
{
cout<<" "<<j;
}
cout<<endl;
}
int main()
{
ll t;
cin>>t;
while(t--)solve();
}