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
空间限制: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 的倍数。
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; }