[题解] 8.13考试 a

题目描述

给定T ∈ {1,2},以及一个正整数N。

当T=1时,求1/x + 1/y = 1/N 的正整数解(x,y) 的个数。

当T=2时,求1/x + 1/y = 1/N! 的正整数解(x,y) 的个数。

输入格式

两个整数T和N

输出格式

一个整数,表示解的个数

输入样例1

1 120

输出样例1

63

输入样例2

2 1439

输出样例2

102426508

数据范围

当T=1时,1<=n<=10^12

当T=2时,1<=n<=10^6

思路解析

首先我们考虑T=1的情况,式子可以化为:

(x+y) / x * y = 1/N => x * y = (x+y) * N => x * y = x * N + y * N => (y-N) * x = y * N

设 z = y-N => y = z+N ,所以 z * x = (z+N) * N => z * x = z * N + N * N => x = N + N * N / z

因为 x 是正整数,所以N * N 是z的倍数,于是解的个数实际上就是 N * N 的约数个数。

我们考虑暴力做法O(n^2)来思考怎么做。

可以发现,将n分解质因数后,n的约数个数=(sum[i]+1) * (sum[i+1]+1) * ... * (sum[i+...]+1)

其中,sum[i]表示质数i的个数。至于为什么应该很好想吧,考虑每个质数取0个,1个,2个...sum[i]个。还不懂的感性理解一下(不是

然后对于T=2的情况,因为N! = 1 * 2 * 3 * ... * N,我们就对于1-n每个数都分解一边质因数然后加起来再用上面的方法算就行了。

分解质因数什么的就不用说了吧。

赋上代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int p=1e9+7;
const int N=1e6+5;
int t,cnt,z[N],sum[N],num[N];
bool flag[N];
ll n,ans=1;
void shai(int len){
  for(int i=2;i<=len;i++){
    if(!flag[i])
      z[++cnt]=i,num[i]=cnt;
    for(int j=1;j<=cnt;j++){
      ll t=z[j]*i;
      if(t>len) break;
      flag[t]=1;
      if(i%z[j]==0) break;
    }
  }
}
int main(){
  scanf("%d%lld",&t,&n);
  if(t==1){
    shai((int)sqrt(n));
    for(int i=1;i<=cnt;i++){
      if(n==1) break;
      while(n%z[i]==0){
      sum[i]++;
      n/=z[i];
      }
      ans=(ans*(ll)(sum[i]*2+1))%p;
    }
    if(n>1)
      ans=(ans*(ll)3)%p;
    printf("%lld",ans);
    return 0;
  }
  else{
    for(int i=2;i<=n;i++){
      int m=i;
      for(int j=2;j*j<=m;j++){
      if(m==1) break;
      while(m%j==0){
        sum[j]++;m/=j;
       }
      }
     if(m>1)
      sum[m]++;
    }
    for(int i=1;i<=n;i++)
      if(sum[i])
    ans=(ans*(ll)(sum[i]*2+1))%p;
    printf("%lld",ans);
    return 0;
  }
  return 0;
}

 

posted @ 2019-08-13 20:12  Biscuits_0819  阅读(98)  评论(0编辑  收藏  举报