2025 暑假集训 Day6
2025.8.9
【HT-072-Div.2】核桃CSP-S组模拟赛 & XRCOI Round 4
A. 异或
定义函数 \(G(x,y) = 2^x - 2^y\)。
给定一个十六进制正整数 \(p\) 以及两个长度为 \(n\) 的序列 \(a, b\),你需要求出以下表达式的值:
\[p \oplus G(a_1, b_1) \oplus G(a_2, b_2) \oplus \cdots \oplus G(a_{n-1}, b_{n-1}) \oplus G(a_n, b_n)
\]
其中 \(\oplus\) 表示按位异或。
注意:
- 输入时,正整数 \(p\) 将以十六进制的形式给出。
- 输出时,你也需要以十六进制的形式输出这个表达式的值。
数据范围:
对于 \(100\%\) 的数据,保证:
- \(0 \leq b_i \leq a_i\)
- \(2^{a_i}, 2^{b_i} \leq p\)
- \(0 < \log_{16} p \leq 2 \times 10^5\)
- \(0 \leq n \leq 2 \times 10^5\)
input
3C315D7
4
2 1
2 1
2 1
2 1
output
3C315D7
首先显然直接模拟是肯定不行的。打开计算器算一下这个 \(G(x,y)\) 发现答案的二进制总是为 \(1111\cdots000\cdots\) 这种形式。如果把原数的二进制从高到低用一个数组 \(a_0,a_1,\cdots,a_{4strlen(p)-1}\) 存起来,对于一个 \(G(x,y)\) 就等价于把第 \([n-l,n-r-1]\) 位取反。可以用一个标记数组 \(t\) 来标记某一位是否要取反,用差分维护即可 但是不知道为什么赛时用了个分块。
赛时代码(AC):
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
constexpr int N=1e6+7;
bool a[N]; //二进制位
int t[N]; //得出每一位要不要取反
string s;
int n;
inline string get(char c)
{if(c=='0') return "0000";if(c=='1') return "0001";if(c=='2') return "0010";if(c=='3') return "0011";if(c=='4') return "0100";if(c=='5') return "0101";
if(c=='6') return "0110";if(c=='7') return "0111";if(c=='8') return "1000";if(c=='9') return "1001";if(c=='A') return "1010";
if(c=='B') return "1011";if(c=='C') return "1100";if(c=='D') return "1101";if(c=='E') return "1110";if(c=='F') return "1111";
return "f**k";
}
inline char get1(char a,char b,char c,char d)
{string s;s.push_back(a);s.push_back(b);s.push_back(c);s.push_back(d);
if(s=="0000") return '0';if(s=="0001") return '1';if(s=="0010") return '2';if(s=="0011") return '3';if(s=="0100") return '4';if(s=="0101") return '5';if(s=="0110") return '6';if(s=="0111") return '7';
if(s=="1000") return '8';if(s=="1001") return '9';if(s=="1010") return 'A';if(s=="1011") return 'B';if(s=="1100") return 'C';if(s=="1101") return 'D';if(s=="1110") return 'E';if(s=="1111") return 'F';
return '-';
}
inline char rev(bool ch,bool k)
{
if(k)
{
if(ch==1) return '0';
else return '1';
}
else return ch+'0';
}
int id[N],len; //分块维护t数组 复杂度 O(sqrt(n))
bool lazy[N];
inline void modify(int l,int r)
{
// cerr<<id[l]<<' '<<id[r]<<endl;
if(l>r) return;
if(id[l]==id[r]) for(int i=l;i<=r;i++) t[i]^=1;
else
{
for(int i=l;id[i]==id[l];i++) t[i]^=1;
for(int i=id[l]+1;i<id[r];i++) lazy[i]^=1;
for(int i=r;id[i]==id[r];i--) t[i]^=1;
}
}
inline void push_down() //把分块的懒标记下传
{
for(int i=0;i<n;i++) t[i]=t[i]^lazy[id[i]];
}
int main()
{
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
cin>>s;
n=s.size()*4;
len=sqrt(n);
s=" "+s;
for(int i=0;i<n;i++) id[i]=i/len+1;
for(int i=0,j=1;i<n;i+=4,j++)
{
string res=get(s[j]);
id[i]=i/len+1;
a[i]=res[0]-'0';
a[i+1]=res[1]-'0';
a[i+2]=res[2]-'0';
a[i+3]=res[3]-'0';
}
int Q,l,r;
cin>>Q;
while(Q--)
{
cin>>l>>r;r--;
l=n-l; r=n-r-2;
modify(l,r);
}
push_down();
for(int i=0;i<n;i+=4) cout<<get1(rev(a[i],t[i]),rev(a[i+1],t[i+1]),rev(a[i+2],t[i+2]),rev(a[i+3],t[i+3]));
return 0;
}
/*
操作(a,b)表示把[a,b-1]取反
*/

浙公网安备 33010602011771号