小Biu闯关

119 篇文章 0 订阅
这篇博客探讨了如何计算特定区间覆盖问题的答案。通过分类讨论,作者解释了在未出现和出现区间交集两种情况下,如何利用等差数列求和公式计算覆盖的数字个数。文章提供了一个公式,并解释了取最小值的原因,最后展示了实现该计算的代码片段。
摘要由CSDN通过智能技术生成

在这里插入图片描述

正题:
首先我们可以知道:它可以覆盖 [ a , b ] , [ 2 a , 2 b ] , [ 3 a , 3 b ] … … [ k a , k b ] ( k > 0 ) [a,b], [2a,2b], [3a,3b]……[ka,kb](k>0) [a,b],[2a,2b],[3a,3b][ka,kb](k>0)
那我们来想怎样计算答案
分类讨论

  1. 未出现区间交集
    通过等差数列求和公式,我们可以算出
    ( ( b − a ) + ( ( p − 1 ) ∗ b − ( p − 1 ) ∗ a ) ) ∗ ( p − 1 ) / 2 ((b-a)+((p-1)*b-(p-1)*a))*(p-1)/2 ((ba)+((p1)b(p1)a))(p1)/2
    其中p表示当完整的区间的个数
    这个式子就是求 [ a , b ] , [ 2 a , 2 b ] , [ 3 a , 3 b ] … … [ p a , p b ] ( p > 0 ) [a,b], [2a,2b], [3a,3b]……[pa,pb](p>0) [a,b],[2a,2b],[3a,3b][pa,pb](p>0) 可以覆盖总共的数字个数
    化简得
    ( ( b − a ) + ( ( p − 1 ) ∗ ( b − a ) ) ) ∗ ( p − 1 ) / 2 ((b-a)+((p-1)*(b-a)))*(p-1)/2 ((ba)+((p1)(ba)))(p1)/2
    p ∗ ( b − a ) ∗ ( p − 1 ) / 2 p*(b-a)*(p-1)/2 p(ba)(p1)/2
    然后加上要求的数的位置和区间右端点 − - 最后一个区间的起始位置即可
    m i n ( x x , p ∗ b ) − p ∗ a + 1 min(xx,p*b)-p*a+1 min(xx,pb)pa+1
    为什么是 min ⁡ \min min 呢,因为直接用xx的话最后有一些没有覆盖到的区间会被算进去,所以要和最后的那个区间的右端点取个 min ⁡ \min min
    所以就是
    p ∗ ( p − 1 ) ∗ ( b − a ) / 2 + p − 1 + m i n ( x x , p ∗ b ) − p ∗ a + 1 p*(p-1)*(b-a)/2+p-1+min(xx,p*b)-p*a+1 p(p1)(ba)/2+p1+min(xx,pb)pa+1
  2. 出现区间交集
    其实和上面差不多
    k ∗ ( k − 1 ) ∗ ( b − a ) / 2 k*(k-1)*(b-a)/2 k(k1)(ba)/2
    其中k代表在区间开始出现交集的那个区间的编号
    此式子和上面的化简过程一样
    再加上要求的数的位置 − - 最后一个不完整的区间的起始位置就可以了
    x x − k ∗ a + 1 xx-k*a+1 xxka+1
    所以就是
    k ∗ ( k − 1 ) ∗ ( k − a ) / 2 + k − 1 + x x − k ∗ a + 1 k*(k-1)*(k-a)/2+k-1+xx-k*a+1 k(k1)(ka)/2+k1+xxka+1
    最后整个代码:
#include<iostream>
#include<cstdio>
using namespace std;
int t;
long long solve(long long n, long long x, long long y)
{
	long long a=(x-1)/(y-x)+1;
	long long b=n/x;
	if(a<=b)
		return a*(a-1)*(y-x)/2+a-1+n-a*x+1;//
	return b*(b-1)*(y-x)/2+b-1+min(n, b*y)-b*x+1;
}
int main()
{
	scanf("%d", &t);
	while(t--)
	{
		long long a, b, x, y;
		scanf("%lld%lld%lld%lld", &a, &b, &x, &y);
		printf("%lld\n", solve(y, a, b)-solve(x-1, a, b));
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值