非常好的一个题:
首先进行化简:$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; }