CSU 1803:2016解题报告

本来是没有写博客的习惯,结果今天回头看自己A过的题,发现根本看不懂代码了,看着题目也完全没有思路,这就比较尬了,因此打算走上这条不归路。

言归正传,题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1803

看到题目,我的第一感觉就是分解因数即2016=1*2016=2*1008=…………对2016分解一下质因数就知道有多少种了,2016 = 2^5 * 3^2 * 7,额,这个手动算起来有些麻烦。而且还有一点,题目要求a*b是2016倍数的数对个数,假设c*d=2016,那么(xc,yd)都满足条件了。这样我们只要求出(c,d)对应的x,y个数就好显然x <= m/c, y <= n/d。这就简单了,开两个数组,储存c,d对应的x,y就好,而对于c,d,一层for循环遍历一遍即可。求出来对应的x,y后又有一个麻烦的问题——判重,显然,2016的倍数也是1008的倍数,所以由容斥原理,我们可以将1008的倍数个数减去一个2016的倍数个数。那么继续算下去的时候,算到504的时候,发现要算出是504的倍数,但不是1008的倍数,也不是2016的倍数(没错,2016是1008的倍数,但我们之前已经减掉了,所以我们存的1008的倍数的个数实际上应该是是1008的倍数,而不是2016的倍数的个数),这个处理再用一层for循环处理就好了,然后最后用两层for循环遍历出i*j==2016的i和j,然后将i的倍数个数乘以j的倍数个数,最后加到计数器上即可。

最后代码如下:



#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>

using namespace std;
typedef long long LL;
int main()
{
//    freopen("in.txt", "r", stdin);
    LL m, n;
    while(~scanf("%lld%lld", &m, &n))
    {
        LL M[2017] = {0}, N[2017] = {0};
        for(int i = 2016; i; -- i)
        {
            M[i] = m/i;
            N[i] = n/i;
            for(int j = i+1; j < 2017; ++ j)
                if(j % i == 0 && 2016 % i == 0 && (2016/i) % (j/i) == 0)
                    N[i] -= N[j];
        }
        LL ans = 0;
        for(int i = 1; i < 2017; ++ i)
            for(int j = 1; j < 2017; ++ j)
                if(i * j == 2016)
                   ans += M[i]*N[j];
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/q1410136042/article/details/76570586