题解:AT_abc138_f [ABC138F] Coincidence

题目

前言

看到题解区都是数位 dp ,然而这题其实只需要稍稍分类讨论一下就行了。

思路

(以下提到的位、位数等描述都是在二进制下)。

一些显而易见的结论

关于位数

易发现,\(x\)\(y\) 必定是位数相同的,(否则异或的结果位数必定等于其较大值,模的结果必定小于等于其较小值)。

关于每一位

结论

再然后,观察到对于每一位必定只有三种情况:

  • \(y\) 中为 \(1\)\(x\) 中为 \(0\)
  • \(y\)\(x\) 中都为 \(1\)
  • \(y\) 中为 \(0\)\(x\) 中为 \(0\)

为什么?

以上三种在当前位上合法是显而易见的,而全部都是这三种情况则全部也就合法了。

\(y\) 中为 \(0\)\(x\) 中为 \(1\) 为什么不行呢?

假设第 \(i\) 位是第一个 \(y\) 中为 \(0\)\(x\) 中为 \(1\) 的位,则此时异或的结果必然会比模的结果多 \(2^{i-1}\) 而这在后面的 \(i-1\) 位是不可能补回来的。

做法

\(r\) 的位数为 \(rd\)\(l\) 的位数为 \(ld\)

枚举 \(x\)\(y\) 的位数,设位数为 \(i\)

\(ld < i < rd\)

因为此时不会有上下界的问题,所以除了最高位之外所有位都有上面提到的三种情况,也就是说此时的答案为:

\[3^{i-1} \]

\(i = ld\)

从高位往地位遍历,设当前遍历到第 \(j\) 位。

\(l\) 的第 \(j\) 位为 \(1\)

此时只有 \(x\)\(y\) 的第 \(j\) 位都为 \(1\) 的情况不会超出范围,即只有一种情况,直接跳过看后面。

\(l\) 的第 \(j\) 位为 \(0\)

此时三种情况都是不会超出范围的,我们分开讨论:

\(y\) 和,\(x\) 中都为 \(1\)

这意味着之后 \(j-1\) 位无论怎么搞都是不会超出范围的,于是我们直接加上 \(3^{j-1}\)

其实并不行,这里需要在乘上一个系数,而这个系数是由其他的两种情况带来的。

其他情况

可以发现这两种情况对于后面的取值是没有影响的,但是却有两种不同的取值,于是我们将后面的答案乘上一个二,也即将上面提到的系数(初始化为一)乘上一个二。

\(i = rd\)

\(i = ld\) 的情况类似,只是当前位为一和为零的做法对调而已。

特判

\(ld = rd\) 时,以上的做法正确性是有问题的,于是需要特判。

一样是从高位往低位遍历,设当前到 \(j\) 位。

\(j\) 位上 \(l\)\(0\),\(r\)\(1\)

显然,这时无论什么情况都不会超。

如果这位 \(x\)\(y\) 都为 \(0\),则之后无论如何都不会比 \(r\) 大,此时的答案即为之后 \(j-1\) 位上只考虑 \(l\) 的方案数,参见 \(i = ld\) 时的做法。

\(x\)\(y\) 都为 \(1\) 时同理。

\(y\) 上为 \(1\)\(x\) 上为 \(0\) 时对后面没有影响,直接往后面遍历就行了。

\(j\) 位上 \(l\)\(1\),\(r\)\(0\)

可以发现这里没有一种情况不超界,直接跳出就行了。

其他情况

其他情况都只有一种取值,且对后面没有影响,直接跳过即可。

最后的特判

判一下 \(x=l,y=r\) 的情况是否合法,如是则答案加一。

代码

代码如下,有问题评论区见。

#include<iostream>
#include<cstdio>
#define ll long long
#define mod 1000000007
using namespace std;
ll l,r;
int main(){
	scanf("%lld%lld",&l,&r);
	if(r==1){
		printf("1");
		return 0;
	}
	ll cr=0,tr=r,cl=0,tl=l;
	while(tr)
		cr++,tr>>=1;
	while(tl)
		cl++,tl>>=1;
	ll da=0,dda=1,qx=1,ddaa;
	ll ans=0;
	if(cl==cr){
		for(ll i=cr-1;i>=1;i--){
			if((r>>(i-1)&1)==(l>>(i-1)&1)){
				if(i==1)ans++;
				continue;
			}
			else if((r>>(i-1)&1)&&(l>>(i-1)&1)==0){
				da=0,qx=1;
				for(ll j=i-1;j>=1;j--){
					if((l>>(j-1)&1)==0){
						dda=1;
						for(ll k=1;k<j;k++){
							dda*=3;
							dda%=mod;
						}
						da+=qx*dda%mod;
						da%=mod;
						qx*=2,qx%=mod; 
					}
				}
				da+=qx;
				da%=mod;
				ans+=da;
				ans%=mod;
				da=0,qx=1;
				for(ll j=i-1;j>=1;j--){
					if((r>>(j-1)&1)){
						dda=1;
						for(ll k=1;k<j;k++){
							dda*=3;
							dda%=mod;
						}
						da+=qx*dda%mod;
						da%=mod;
						qx*=2,qx%=mod; 
					}
				}
				da+=qx;
				da%=mod;
				ans+=da;
				ans%=mod;
				if(i==1)ans++;
			}
			else break;
		}
		printf("%lld",ans); 
		return 0;
	} 
	for(ll i=cr-1;i>=1;i--){
		if(r>>(i-1)&1){
			dda=1,ddaa=1;
			for(ll j=1;j<i;j++){
				 
				dda*=3;
				dda%=mod;
			}
			da+=qx*dda%mod;
			da%=mod;
			qx*=2;
			qx%=mod;
		}
	}
	da+=qx;
	da%=mod;
	ans+=da;
	ans%=mod;
	for(ll i=cl+1;i<cr;i++){
		da=1;
		for(ll j=1;j<i;j++){
			da*=3;
			da%=mod;
		}
		ans+=da;
		ans%=mod;
	}
	da=0,qx=1;
	for(ll i=cl-1;i>=1;i--){
		if((l>>(i-1)&1)==0){
			dda=1;
			for(ll j=1;j<i;j++){
				dda*=3;
				dda%=mod;
			}
			da+=qx*dda%mod;
			da%=mod;
			qx*=2,qx%=mod;  
		}
	} 
	da+=qx;
	da%=mod; 
	ans+=da;
	ans%=mod;
	
	printf("%lld",ans);
	return 0;
}
posted @ 2025-11-08 23:27  hyx1gg  阅读(2)  评论(0)    收藏  举报