求大赏关
  • 板块灌水区
  • 楼主GavinCayne
  • 当前回复1
  • 已保存回复1
  • 发布时间2023/9/5 21:24
  • 上次更新2023/11/2 22:37:21
查看原帖
求大赏关
523754
GavinCayne楼主2023/9/5 21:24

原因是 【中文】与【英文、数字或公式】之间应以半角空格隔开;

各位大佬帮帮蒟蒻看看哪里没留神,这是第四次打回了。。。

此篇题解是为补充前两位大佬(均为排名前200的超级大犇)的题解。毕竟人家和本蒟不在同一水平,简单说几句就以为我这样的小蒟蒻能一下搞懂找到门路(嘤嘤嘤)。

题目大意

传送门

给你 nn 和 mm,求 11 到 nn 所有的数异或上 11 到 mm 所有的数结果相加的总和。

整理一波思路

  1. 暴力计算。直接双环枚举 nn 和 mm,把每一次异或的值算出来再加。这样的话时间复杂度为 O(Tnm)O(Tnm)。由于 n,m≤1016n,m\le10^{16},必炸。
  2. 考虑从异或本身定义出发。只有当 aa 和 bb 某一二进制位一个为 11 且另一个为 00 时异或值为 11。即当进行到第 nownow 位,若 nn 这边取了一个某位为 11 的数,mm 这边要取一个同一位为 00 的数才能使结果产生贡献。不妨设 nn 这边有 xx 个 nownow 位为 11,mm 这边有 yy 个 nownow 位为 11,那么 nn 这边贡献(该位为 11 的数的个数)即可表示为 x×(m−y)x\times(m-y),同理 mm 这边的贡献为 y×(n−x)y\times(n-x)。nownow 位为 11 时自身数值为 2now2^{now},结果用总贡献乘数值,为 [x×(m−y)+y×(n−x)]×2now[x\times(m-y)+y\times(n-x)]\times2^{now}。然后找到每一位按这种方案求出贡献,加在一起即可。
  3. 如何找到每一位有几个数为 11?(重点来啦,两位奆佬没细讲)设现在在第 nownow 位。那么,不考虑高位,第 nownow 位为 00 的数从 00 到 2now−12^{now}-1,一共 2now2^{now} 个;而第 nownow 位为 11 的数从 2now2^{now} 到 2now+1−12^{now+1}-1,也是 2now2^{now} 个。那么我们就可以得出第 now+1now+1 位的数值中第 nownow 位为 11 的占一半!只要我们算出 n÷2now+1n\div2^{now+1} 再乘 2now2^{now} 不就知道这一位有几个数为 11 了吗?(有的人会问这是不是多此一举,直接用 n÷2n\div2 不就得了,但实际上 nownow 可以取到小于等于 nn 的最大偶数次幂,换句话说 2now+12^{now+1} 很有可能超过 nn,也就是除法运算时 nn 不够除。)如果 nn 不是 22 的整数次幂,结果必然产生余数。余数中前 2now−12^{now}-1 是第 nownow 位为 00(与前文相比排除了 00,即没余数),那么 n mod 2now+1≤2now−1n\bmod2^{now+1}\le 2^{now}-1 时贡献为 00,反之就减去前 2now−12^{now}-1,贡献为 n mod 2now+1−(2now−1)n\bmod2^{now+1}-(2^{now}-1)。

喜闻乐见的代码时间

为了偷懒,本蒟把 nownow 定义为了 2now2^{now},用 ii 来枚举当前的位置,观看时请务必注意。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int M=998244353;
int t,cnt[33][3];
int times(int x,int y)
{
	return ((x%M)*(y%M))%M;
}
int pl(int x,int y)
{
	return ((x%M+y%M)%M+M)%M;
}
inline int read()
{
	int f=1,k=0;
	char c=getchar();//读入一个字符 
	//非数字 
	while(c<'0'||c>'9')//读到空格后
	{
		if(c=='-')f=-1;//读到负数  
		c=getchar();//两个功能:读取负号后面的数字或者读入空格等。 
	}
	//数字 
	while(c>='0'&&c<='9')
	{
		k=(k<<1)+(k<<3)+(c^48);
		c=getchar();//一位一位读入数字 
	}
	return f*k;	
}
signed main()
{
	t=read();
	while(t--)
	{
		int n=read(),m=read(),ans=0,now=1;
		memset(cnt,0,sizeof(cnt));
		for(register int i=0;(1ll<<i)<=max(n,m);i++)
		{		
			int f=now<<1;
			cnt[i][1]=(now<=n?(now*(n/f)+(n%f+1>=now?(n%f-now+1):0)):0);//1~n第i位几个数值位1 
			cnt[i][2]=(now<=m?(now*(m/f)+(m%f+1>=now?(m%f-now+1):0)):0);//1~m第i位几个数值位1 
			ans=pl(ans,times(now,pl(times(cnt[i][1],(m-cnt[i][2])),times(cnt[i][2],n-cnt[i][1]))));
			now<<=1;
		}
		cout<<ans<<endl;
	}
	return 0;
}

最后提醒大家时刻不要忘记模 998244353998244353!完结撒花!感谢观看!

2023/9/5 21:24
加载中...