以下代码转自巨佬,仅作为本人笔记参考
容斥定理 打表
int build(int k, int l, int r) {
if (l == r) {
return k;
}
int mid = (l + r) >> 1;
int res=0;
res=max(build(k << 1, l, mid),res);
res=max(build(k << 1 | 1, mid + 1, r),res);
return res;
}
void fun(int x){
stack<int>ss;
while(x){
ss.push(x%2);
x/=2;
}
while(!ss.empty()){
cout<<ss.top();
ss.pop();
}
cout<<endl;
}
signed main() {
ll l, r;
// cin >> l >> r;
// cout << (fx(r) ^ fx(l - 1)) << endl;
for(int i=1;i<=200;i++){
fun(build(1,1,i));
}
return 0;
}
我们用这串代码打个表,看看最大值出现的规律,结果是:
1
11
101
111
1001
1101
1101
1111
10001
11001
11001
11101
11101
11101
11101
11111
100001
110001
110001
111001
111001
111001
111001
111101
111101
111101
111101
111101
111101
111101
111101
111111
1000001
1100001
1100001
1110001
1110001
1110001
1110001
1111001
1111001
1111001
1111001
1111001
1111001
1111001
1111001
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111101
1111111
观察规律,在 2k +1至 2k+1, k>3中,连续的异或结果是0;
又根据容斥定理,我们最后可以仅仅观察 f(2k)、 f(2k+1)和 f(n)的值。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define gcd(a, b) __gcd(a,b)
const long long mod = 1e9 + 7;
const int maxn = 1e6 + 5;
int lowbit(int x) { return x & -x; }
bool ispow(int n) { return (n & (n - 1)) == 0; }//O(1) 判断是否是 2^k(2的k次方)
#define ll long long
ll n;
//计算n节点线段树层数
int _Logu(ll n) {
int l = 0, r = 63; //一般不会超过63层,二分是个好选择,遍历一次也行
while (l < r) {
int mid = (l + r) >> 1;
if ((1ll << mid) < n) l = mid + 1;
else r = mid;
}
return l;
}
ll f(ll n, ll dep) {
if (ispow(n) || ispow(n - 1))
return 2 * n - 1;
return (f(n >> 1, dep - 1) + (1ll << dep));
}
ll f(ll n) { return f(n, _Logu(n)); }
ll fx(ll n) {
if (n == 0) return 0;
ll ret = 0;
map<int, bool> m;
#define add(x) if((x)<=n&&!m[x]) {m[x]=true;ret^=f(x);} //这里特判了1,2,3,4
for ( ll i = 1; i <= n;
i <<= 1) {
add(i)
add(i + 1)
}
if ((n & 1) == 0 && !m[n]) ret ^= f(n);
return ret;
}
int build(int k, int l, int r) {
if (l == r) {
return k;
}
int mid = (l + r) >> 1;
int res=0;
res=max(build(k << 1, l, mid),res);
res=max(build(k << 1 | 1, mid + 1, r),res);
return res;
}
void fun(int x){
stack<int>ss;
while(x){
ss.push(x%2);
x/=2;
}
while(!ss.empty()){
cout<<ss.top();
ss.pop();
}
cout<<endl;
}
signed main() {
ll l, r;
cin >> l >> r;
cout << (fx(r) ^ fx(l - 1)) << endl;
return 0;
}
1749

被折叠的 条评论
为什么被折叠?



