《Lecxcy and SakuKumo》

非常好的一个题:

首先进行化简:$yn! - xn! = xy Rightarrow  yn! - xn! - xy + (n!)^{2} = (n!)^{2} Rightarrow (n!+y)(n!-x) = (n!)^{2}$

可以看到的是,式子左边是一个完全平方数。

那么显然式子的左边是它的两个因子,所以我们只需要找出右边的所有因子然后 - 1(因为对于n!的情况,x,y都要为0.这于题目x,y都是正整数冲突)。

那么为什么对于所有的因子(除n!)都满足x,y都是正整数满足呢。

因为n! 即为根号因子的分界线,若x,y都是正整数,那么n! + y 和 n! - x 刚好关于这个分界线两边分布,所以满足因子的对称性,肯定满足。

所以我们求出所有因子的出现次数,然后由唯一分解定理的扩展即可求得总因子数。

这里我们虽然应该求n! ^ 2的因子,但是我们可以对n!质因子分解,然后看成两个n!,那么每次计算因子个数都加2即可。

这样操作复杂度显然有点过高,我们可以对询问离线,然后从小到大去分解,这样避免重复分解。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e6 + 5;
const int M = 1e7 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e18 + 5
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

int prime[N],tot = 0;
LL cnt[M],ans[N];
bool vis[M];
void init() {
    for(int i = 2;i < M;++i) {
        if(!vis[i]) {
            prime[++tot] = i;
        }
        for(int j = 1;j <= tot && prime[j] * i < M;++j) {
            vis[prime[j] * i] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}
LL quick_mi(LL a,LL b) {
    LL re = 1;
    while(b) { 
        if(b & 1) re = re * a % Mod;
        a = a * a % Mod;
        b >>= 1;
    }
    return re;
}
struct Node{
    int id,num;
}p[N];
bool cmp(Node a,Node b) {
    return a.num < b.num;
}
int main()
{
    init();
    int ca;ca = read();
    for(int i = 1;i <= ca;++i) {
        p[i].id = i,p[i].num = read();
    }
    sort(p + 1,p + ca + 1,cmp);
    int pre = 1;
    p[0].id = 0;
    for(int now = 1;now <= ca;++now) {
        if(p[now].num == pre) ans[p[now].id] = ans[p[now - 1].id];
        else {
            for(int i = pre + 1;i <= p[now].num;++i) {
                if(!vis[i]) {
                    cnt[i] += 2;
                    continue;
                }
                int x = i;
                for(int j = 1;j <= tot && prime[j] <= x;++j) {
                    if(x == 1 || !vis[x]) break;
                    if(x % prime[j] == 0) {
                        while(x % prime[j] == 0) {
                            cnt[prime[j]] += 2;
                            x /= prime[j];
                        }
                    }
                }
                if(x != 1) cnt[x] += 2;
            }
            LL ma = 1;
            for(int i = 1;i <= tot;++i) {
                int x = prime[i];
                if(x > p[now].num) break;
                if(cnt[x] == 0) continue;
                ma = ma * (cnt[x] + 1) % Mod;
            }
            ans[p[now].id] = (ma - 1) * quick_mi(2,Mod - 2) % Mod;
            pre = p[now].num;
        }
    }
    for(int i = 1;i <= ca;++i) printf("%lld
",ans[i]);
    system("pause");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/14652029.html