bzoj2721 [Violet 5]樱花

 

分析:这道题对于我这种蒟蒻来说还是很有难度啊。

     思路非常巧妙,既然不定方程要有有限个数解,那么这个肯定会对解有所限制,也就是本题中的正整数.这个时候我们要表示出方程中的一个根x,设z = n!,那么x=yz/(y-z),这样的话不能得到答案,我们要得到的式子一定是分母只能有乘积的形式,并且同一个字母不能同时在分子分母中出现,因为我们就是利用正整数的整除性来求解的,可以看出x和y都大于z,所以我们设y = z + d,带入,就消掉了y,可以得到x = z^2/d + z,因为x是正整数,所以z^2/d必须是整数,所以d是z^2的因子,那么我们只需要求出z^2有多少个约数就好了.

     求约数的个数要用到乘法原理和线性筛,z可以表示为p1^k1 * p2^k2 * p3^k3*...*pn^kn这种形式,每个质因数可以选1到ki个或不选,而约数就是由不同的质因子通过相乘组合起来的,所以约数的个数就等于(k1 + 1)*(k2 + 1)*...*(kn + 1),而我们要求z^2的因子个数,总不可能直接平方吧......可以发现每个质因子的次数扩大了两倍,那么每个质因子就有2*ki + 1种选择,和上面一样直接乘法原理出答案.

     因为z = n!,所以枚举1到n中的质数i的倍数,看i出现了几次,就能得到ki.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>

using namespace std;

const int mod = 1000000007;

int prime[1000010], tot, cnt[1000010],n;
bool vis[1000010];

long long ans = 1;

void init()
{
    for (int i = 2; i <= n; i++)
    {
        if (!vis[i])
            prime[++tot] = i;
        for (int j = 1; j <= tot; j++)
        {
            if (prime[j] * i > n)
                break;
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0)
                break;
        }
    }
}

int main()
{
    scanf("%d", &n);
    init();
    for (int i = 1; i <= tot; i++)
        for (int j = prime[i]; j <= n; j += prime[i])
            for (int k = j; k % prime[i] == 0; k /= prime[i])
                cnt[i]++;
    for (int i = 1; i <= tot; i++)
        ans = (ans * 1LL * (cnt[i] * 2 + 1) % mod) % mod;

    printf("%lld\n", ans);
    return 0;
}

 

    

 

posted @ 2017-08-18 16:16  zbtrs  阅读(266)  评论(0编辑  收藏  举报