题解 T1

传送门

没做出来自闭了

首先找性质:

  • 关于一个序列所有子序列的异或和之和:
    考虑每一位的贡献,发现若存在一个数这一位是 1,则它一定会贡献 \(2^{n-1}\)
    证明(令这一位为 1 的有 \(x(x>0)\) 个):
    \(\operatorname{contribution}=2^{n-x}\sum\limits_{i=0}^x[2\nmid i]\binom{x}{i}=2^{n-1}\)
    最后一步是怎么过来的呢?考虑前 \(n-1\) 位任选,通过调整最后一位满足 \([2\nmid i]\) 的限制
    调整与否一定是一个满足一个不满足,得证

然后可以发现 \(n>2\) 是没用的,当做 \(n=2\) 即可
现在问题变为选出 \(x, y\in[l, r]\),问 \(x\or y\) 的取值个数
AGC015D A or...or B Problem
做法是考虑这个 l,r
令其最高不同位为 \(2^k\),高于这一位的部分都去掉
\([l, 2^k)\) 内的数能或出来的范围仍在 \([l, 2^k)\)
然后令 \(2^t\)\(r\) 的次高位,则 \([2^k, r]\) 内的数能或出来的范围为 \([2^k, 2^k+2^{t+1})\)
考虑 \([l, 2^k)\)\([2^k, r]\) 交互能或出来的东西
等价于去掉第 \(k\) 位求 \([0, r], [l, 2^k)\) 能或出的范围
因为取或后不可能变小,所以 \([r, l]\) 这一段不能或出
所以就可以算范围了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, l, r;

namespace force{
	int a[N];
	int uni[N], usiz;
	int calc() {
		int lim=1<<n, sum=0;
		for (int s=0; s<lim; ++s) {
			int tem=0;
			for (int i=1; i<=n; ++i) if (s&(1<<(i-1))) tem^=a[i];
			sum+=tem;
		}
		return sum;
	}
	void dfs(int u) {
		if (u>n) {uni[++usiz]=calc(); return ;}
		for (int i=l; i<=r; ++i) a[u]=i, dfs(u+1);
	}
	void solve() {
		usiz=0;
		dfs(1);
		sort(uni+1, uni+usiz+1);
		usiz=unique(uni+1, uni+usiz+1)-uni-1;
		cout<<usiz<<endl;
	}
}

namespace task{
	void solve() {
		ll ans=0;
		if (l==r) {puts("1"); return ;}
		int x=1ll<<(63-__builtin_clzll(l^r));
		// cout<<"x: "<<x<<endl;
		l&=x-1; r&=x-1;
		ans+=x-l;
		int r1=0;
		if (r) r1=(1ll<<(64-__builtin_clzll(r)))-1;
		// cout<<"r1: "<<r1<<endl;
		ans+=r1+1; ans+=x-l;
		if (r1>=l) ans-=r1-l+1;
		printf("%lld\n", ans);
	}
}

signed main()
{
	freopen("a.in", "r", stdin);
	freopen("a.out", "w", stdout);

	int T=read();
	while (T--) {
		n=read(); l=read(); r=read();
		if (n==1) printf("%lld\n", r-l+1);
		else task::solve();
		// else force::solve();
	}
	
	return 0;
}
posted @ 2022-03-12 21:11  Administrator-09  阅读(3)  评论(0编辑  收藏  举报