jzoj3084-超级变变变【数学】

版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/86611138

正题


题目大意

定义函数
f ( x ) { x 1 ( x % 2 = = 1 ) x / 2 ( x % 2 = = 0 ) f(x)\left\{\begin{matrix} &x-1(x\%2==1)\\ & x/2(x\%2==0) \end{matrix}\right.
一次变化是将 x = f ( x ) x=f(x)
A B A\sim B 之间有多少个数可以变化到 k k


解题思路

其实就是 f ( x ) = x / 2 f(x)=\lfloor x/2 \rfloor
计算 1 B 1\sim B 减去 1 A 1 1\sim A-1
然后考虑倒推,若 x R x\leq R
2 n k + x 2 n = k \lfloor \frac{2^nk+x}{2^n} \rfloor=k
k + x 2 n = k \lfloor k+\frac{x}{2^n} \rfloor=k
因为 k k 为整数,直接调出
k + x 2 n = k k+\lfloor \frac{x}{2^n} \rfloor=k
x 2 n = 0 \lfloor \frac{x}{2^n} \rfloor=0
那么当 x < 2 n x<2^n 2 n k + x R 2^nk+x\leq R
枚举 n n ,那么 x x 的可取个数 2 n 2^n
k k 为偶数时,有可能是由 k + 1 k+1 变来的,需要特判。


c o d e code

#include<cstdio>
#define ll long long
using namespace std;
ll k,a,b,ans;
ll get_ans(ll x)
{
	if(k<=1) return x;
	ll z=1,ans=0;
	while(z*k<=x){
		ans+=z;
		if(z*k+z-1>x) ans-=z*k+z-1-x;
		z*=2;
	}
	return ans;
}
int main()
{
	scanf("%lld%lld%lld",&k,&a,&b);
	ans+=get_ans(b)-get_ans(a-1);
	if(k&&!(k&1)) k++,ans+=get_ans(b)-get_ans(a-1);
	printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/86611138