2019牛客国庆集训派对day7 A 2016

链接:https://ac.nowcoder.com/acm/problem/52800
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld

题目描述

给出正整数 n 和 m,统计满足以下条件的正整数对 (a, b) 的数量:
1. 1≤a≤n,1≤b≤m
2. a×b 是 2016 的倍数。

输入描述:

输入包含不超过 30 组数据。
每组数据包含两个整数 n, m (1≤n,m≤109).

输出描述:

对于每组数据,输出一个整数表示满足条件的数量。
示例1

输入

32 63

输出

1
示例2

输入

2016 2016

输出

30576
示例3

输入

1000000000 1000000000

输出

7523146895502644



思路:
a*b%mod ==0 -> (a%mod)*(b%mod)%mod ==0
所以 求a*b=k*2016即(a*2016+a1)(b*2016+b1)=k*2016 ->a*b*2016^2+(a+b)*2016+a1*b1 = k*2016;
那么a*b要是2016的倍数的话,就要满足a1*b1是2016的倍数
1<=a1<=2015,1<=b1<=2015;
这里有两种做法
方法一:
正向思维:就是直接求ans;

代码:
#include<iostream>
#include<math.h>
using namespace std;
typedef long long ll;
int main(){
    ll i,j,ans,a,b,n,m;//i,j其实是余数
     while(cin>>n>>m){  
        ans=0;
        for(i=1;i<=min((ll)2016,n);i++){//这里是2016,因为是直接求ans的,所以要到边界2016,相当于正好是倍数关系,这里是1-2016,而不能是0-2015
        
for(j=1;j<=min((ll)2016,m);j++){ if(i*j%2016==0){ a=(n-i)/2016+1;//加一就是包括自己,比如说4033=(2*2016+1),中a=3,就是包括了1,2017,4033这三个数 b=(m-j)/2016+1; ans+=a*b; } } } cout<<ans<<endl; } return 0; }
这题其实是有点暴力的,就是把余数i从1一直到2016全部遍历一遍,然后j也是,把i*J==2016的全算进去,不过是聪明的暴力


方法二:
逆向思维:n*m-Ans =ans;
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int main(){
    int n,m;
    while(cin >> n >> m){
        long long ans = (ll)n * m;
        for(int i = 1; i <= min(2015,n); i++){//这道题是逆向思维,i这里是2015,因为是做减法,就是说把i*j!=2016的减去,i%2016的余数是从1-2015,所以这里是2015
            for(int j = 1; j <= min(2015,m); j++){
                if(i * j % 2016 != 0)
                    ans -= (ll)((n - i) / 2016 + 1) * ((ll)(m - j) / 2016 + 1);
            }
        }
        cout << ans <<endl;
    }
    return 0;
}





原文地址:https://www.cnblogs.com/lusiqi/p/11632142.html