CCPC——咕咕的计数题

题目:链接

咕咕最近在学习初等数论,并且对下取整函数产生了极大的兴趣。下取整函数是指一个函数,自变量为 一个实数,因变量为一个整数,这个整数恰好是小于或等于自变量的最大的整数,通常记做 ⌊x⌋。例如, ⌊2.5⌋ = 2,⌊2⌋ = 2,⌊−2.5⌋ = −3。
 咕咕发现,给定一个 a,并不是所有的自然数 n 都存在一个正整数 i 使得 ⌊n/i⌋ = a。那么,如果给定 l,r,咕咕好奇在区间 [l,r] 中有多少个正整数能使这个等式有正整数解 i 呢?
 那么,聪明的你,你能告诉咕咕吗? 

输入

第一行有一个整数 T(1 ≤ T ≤ 106),表示数据组数。接下来有 T 行,每行有三个数 a,l,r(1 ≤ a ≤ 1018,1 ≤ l ≤ r ≤ 1018),表示一组询问。 

输出

输出 T 行,对每组询问,输出一个整数表示答案。 

样例输入 Copy

4
5 7 10
7 39 42
1000 1000 1000
27 100 1000

样例输出 Copy

1
2
1
617

提示

数据范围
当 n = 39,a = 7 时,能找到 i = 5 使得 ⌊39 /5 ⌋ = 7。

 

题解:

由题意可知,满足条件的n分布在如下区间:

1倍区间:[a,a+1)      个数:1

2倍区间:[2a,2(a+1))       个数:2

3倍区间:[3a,3(a+1))       个数:3

……

a倍区间:[a*a,a(a+1))      个数:a

a+1倍区间开始每个区间都有重叠部分,可以推出a*a+1之后的数均满足题意

对于[l,r]区间内的数,先计算出[1,r]内符合题意个数,再计算出[1,l-1]内符合题意个数,取差即为解。!!!!

!!!!注意

输出时必须使用printf输出格式,否则会超时。

#include <bits/stdc++.h>
#define ll long long
using namespace std;

ll T,l,r,a;

ll solve(ll n)
{
	if(n<1) return 0;
	ll ans=0;
	ll k=n/a;
	if(k>a)
	{
		ans+=((a+1)*a/2);
		ans+=n-(a+1)*a+1;
//		cout<<ans<<endl;
//		if(n>=k*(a+1))
//		{
//			ans+=(a+1);
//		}
//		else if(n>=k*a+k-a-1)
//		{
//			ans+=(n-k*a-k+1+a);
//		}
//		cout<<ans<<endl;
	}
	else
	{
		ans+=(k*(k-1)/2);
		if(n>=k*(a+1))
		{
			ans+=k;
		}
		else
		{
			ans+=(n-k*a+1);
		}
	}
	return ans;
}

int main()
{
	ios::sync_with_stdio(false); 
	cin>>T;
	while(T--)
	{
		cin>>a>>l>>r;
		ll ans;
		ans=solve(r)-solve(l-1);
		printf("%lld\n",ans);
	}
	return 0;
}

反思:比赛时推出规律,但是直接计算[l,r]区间情况太多,也是没有考虑完全的原因,一直答案错误;

           通过计算[1,r],[1,l-1]区间,减少了讨论情况的次数。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值