雨打芭蕉叶

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

第一题:abc048b  B - Between a and b ...

 

问题描述

给定非负整数 a 和 b(a≤b),以及一个正整数 x。在 a 和 b 之间(包括 a 和 b)的整数中,有多少个可以被 x 整除?

约束条件

  • 0≤a≤b≤1018         1≤x≤1018

输入

输入从标准输入以以下格式给出:

a b x

输出

打印在 a 和 b 之间(包括 a 和 b)的整数中,可以被 x 整除的数的个数。


样例输入 1

4 8 2

样例输出 1

3

在 4 和 8 之间(包括 4 和 8)的整数中,有三个可以被 2 整除的数:4、6 和 8。


样例输入 2

0 5 1

样例输出 2

6

在 0 和 5 之间(包括 0 和 5)的整数中,有六个可以被 1 整除的数:0、1、2、3、4 和 5。


样例输入 3

9 9 2

样例输出 3

0

在 9 和 9 之间(包括 9 和 9)的整数中,没有可以被 2 整除的数。


样例输入 4

1 1000000000000000000 3

样例输出 4

333333333333333333

注意整数溢出。

 

 

分析:直接暴力枚举,肯定会超时,那么我们可以思考:从左端点a包含x的个数到右端点b包含x的个数是单调递增的,那么我们只需要计算出左端点a包含x的个数和右端点b包含x的个数,然后做差就是a—b范围内整除x的个数,通过推导样例发现,左端点需要特殊处理一下,代码如下:

#include<bits/stdc++.h>
using namespace std;
long long a,b,x;
int main()
{
    cin>>a>>b>>x;
    if(a%x==0)
    cout<<b/x-a/x+1;
    else
    cout<<b/x-a/x;
    return 0;
}

 

 

第二题:abc131cL. C - Anti-Division

题目描述

给定四个整数A,B,C和D。找出在A和B之间(包括A和B)不能被C和D整除的整数个数。


约束条件

  • 1≤A≤B≤1018         1≤C,D≤109        输入中的所有值都是整数。

输入

从标准输入以以下格式给出输入:

A B C D


输出

打印在A和B之间(包括A和B)能被C和D整除的整数个数。


样例输入1

4 9 2 3

样例输出1

2

5和7满足条件。


样例输入2

10 40 6 8

样例输出2

23


样例输入3

314159265358979323 846264338327950288 419716939 937510582

样例输出3

532105071133627368

 

 

题目分析:本题暴力枚举显然也不可取

那么我们分析:要找出A和B之间不能被C、D整除的数的个数,不妨先找出能被C、D整除的数的个数,然后用总数做减法即可。接下来,我们可以分步骤进行:

1、 先找出A和B之间能被C整除的数的个数,这个问题的解决方法同上一题一模一样。

2、 再找出A和B之间能被D整除的数的个数,这个问题的解决方法同上一题一模一样。

但是我们通过样例1分析:4 9 2 3   4-9之间能被2整除的有4 6 8,4-9之间能被3整除的有6 9,他们有个重复数6,再举例比如4 13 2 3  4-13之间能被2整除的有4 6 8 10 12

4-13之间能被3整除的有6 12 ,他们有两个重复数6 12,那么6正好是2和3的最小公倍数,凡是最小公倍数的倍数的数都出现了重复,因此需要再求出来A和B之间能被C和D的最小公倍数整除的数的个数,去掉这些重复的就是答案~。

代码如下:

 

#include <bits/stdc++.h>
using namespace std;
 
int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
int main()
{
    long long a,b,c,d,ans1,ans2,ans3,gb,zs,nc;
    cin >> a >> b >> c >> d;
    gb=(c*d)/gcd(c,d);//求最小公倍数 
    if(a%c==0)//求a-b之间能被c整除的数的个数 
        ans1=b/c-a/c+1;
    else ans1=b/c-a/c;
    if(a%d==0)//求a-b之间能被d整除的数的个数 
        ans2=b/d-a/d+1;
    else ans2=b/d-a/d;
    if(a%gb==0)//求a-b之间能被最小公倍数整除的数的个数 
        ans3=b/gb-a/gb+1;
    else ans3=b/gb-a/gb;
    zs=b-a+1;//a-b之间所有的数
    nc=ans1+ans2-ans3;//能被a,b整除的数 = 能被a整除的数 + 能被b整除的数 - 能被a和b的最小公倍数整除的数(重复的数),可通过样例推出结论 
    cout<<zs-nc;//不能被整除的数的个数 
    return 0;
}

 

第三题:abc133cL. C - Remainder Minimization

题目描述

给定两个非负整数 L 和 R。我们将选择两个整数 i和 j,使得 L≤i<j≤R。求 (i×j) mod 2019 的最小可能值。

约束条件

  • 输入的所有值都是整数。
  • 0≤L<R≤2×109

输入

从标准输入以以下格式给出输入:

L R

输出

打印出在给定条件下选择 i和 j 时,(i×j) mod 2019的最小可能值。


样例输入 1

2020 2040

样例输出 1

2

当 (i,j)=(2020,2021) 时,(i×j) mod 2019=2。


样例输入 2

4 5

样例输出 2

20

我们只有一个选择:(i,j)=(4,5)。

 

题目分析:暴力枚举依然会超时

那么我们想,

思路1:如果L或R只要有一个能整除2019,那么肯定能找出i、j使得(i×j) mod 2019=0

思路2:计算出左端点L和右端点R分别包含2019的个数(此处就要用到第一题所讲的解题思路),如果左端点包含的个数小于右端点包含的个数(此处就要用到第一题所讲的解题思路),说明在L和R之间一定包含一个数能整除2019,同样可以找出i、j使得(i×j) mod 2019=0。

思路3:排除上述两种情况,那么需要枚举的区间就只剩下最多2019个数,所以暴力枚举所有情况,时间复杂度为2019*2019,问题得解,代码如下:

#include <bits/stdc++.h>
using namespace std;
long long L,R;
int main()
{
    scanf("%lld%lld",&L,&R);
    if(L%2019==0||R%2019==0)  //只要有一个端点包含2019,那么乘积%2019的最小结果肯定为0 
    {
        cout<<0<<endl;
        return 0;
    }
    int u=L/2019;//左端点之前包含2019的个数 
    int v=R/2019; //右端点之前包含2019的个数 
    if(u<v)//说明左右端点之间肯定包含一个2019的倍数 
    {
        cout<<0<<endl;
        return 0;
    }
    long long ans=2020;
    for(long long i=L;i<=R;i++)//暴力枚举,最多2019*2019次循环 
    {
        for(long long j=i+1;j<=R;j++)
            ans=min((i%2019*j%2019)%2019,ans);//同余原理 
    }
   cout<<ans<<endl;
    return 0;
}

 

posted on 2024-11-25 11:10  雨打芭蕉叶  阅读(40)  评论(0)    收藏  举报