Hetao P10483 [XRCOI Round 4] 异或 题解 [ 黄 ] [ 进制 ] [ 差分 ]
异或:蒟蒻的第三道公开赛题 qwq。
#1~4
将 \(p\) 转化为十进制数,然后暴力求每次操作的数,直接模拟即可。
#5~8
正解的弱化版,是留给将十六进制转二进制实现较劣或者暴力区间修改的,时间复杂度是 \(O(n^2)\) 的,具体见后文。
#9~12
观察该性质有何意义,把 \(a=b+1\) 带入函数中,得 \(G(b+1,b)=2^{b+1}-2^{b}=2^b\),也就是说,我们每次操作将 \(p\) 与 \(2^b\) 异或。
既然是与 \(2\) 的整数次幂异或,并且异或是在二进制下进行的,因此我们要先将十六进制数转化为二进制数。
由于十六进制数的每位数小于 \(16=2^4\),所以我们可以把十六进制数中的每一位数转化为一个位数为 \(4\) 的二进制数来表示。具体的实现上,可以通过 map 储存每一个字母转换为 \(4\) 位二进制数后对应什么,然后重新求出二进制数即可。
那么对于二进制数和 \(2^b\) 异或是容易的,直接将二进制数的第 \(b\) 位取反即可。
#13~20
继续观察这个函数有什么意义,不难发现:
\[G(a,b)=2^a-2^b=2^{a-1}+2^{a-1}+2^b=2^{a-1}+2^{a-2}+2^{a-2}+2^b = \dots = 2^{a-1}+2^{a-2}+\dots+2^{b+1}+2^b
\]
因此,我们需要将原二进制数中的第 \(b\sim a-1\) 位全部取反,这个显然可以用差分实现。时间复杂度为 \(O(n)\)。
代码如下:
#include <bits/stdc++.h>
using namespace std;
int n,a,b;
string s,res;
unordered_map<int,char>ist={{0,'0'},{1,'1'},{2,'2'},{3,'3'},{4,'4'},{5,'5'},{6,'6'},{7,'7'},{8,'8'},{9,'9'},{10,'A'},{11,'B'},{12,'C'},{13,'D'},{14,'E'},{15,'F'}};
unordered_map<char,int>mp={{'0',0},{'1',1},{'2',2},{'3',3},{'4',4},{'5',5},{'6',6},{'7',7},{'8',8},{'9',9},{'A',10},{'B',11},{'C',12},{'D',13},{'E',14},{'F',15}};
bitset<800005>ori,f,ans;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>s;
for(int i=0,k=s.length()-1;i<s.length();i++,k--)
{
int tmp=mp[s[k]];
for(int j=i*4;j<=i*4+3;j++)
{
ori[j]=(tmp&1);
tmp>>=1;
}
}
cin>>n;
while(n--)
{
cin>>a>>b;
f[a]=(f[a]^1);
f[b]=(f[b]^1);
}
for(int i=1;i<s.length()*4;i++)f[i]=(f[i]^f[i-1]);
ans=(ori^f);
for(int i=0;i<s.length();i++)
{
int tmp=0,tms=1;
for(int j=i*4;j<=i*4+3;j++)
{
tmp+=tms*ans[j];
tms*=2;
}
res+=ist[tmp];
}
for(int i=res.length()-1,legal=0;i>=0;i--)
{
if(res[i]!='0')legal=1;
if(legal)cout<<res[i];
}
return 0;
}
感觉这题就是涉及到一个进制的转化,以及一个简单结论在二进制下的表现,还是比较简单的。

浙公网安备 33010602011771号