爱奇艺-笔试刷题

题目描述:

/**
考虑定义在两正整数上的函数SSR(平方根之和的平方):
SSR(A, B) = (sqrt(A) + sqrt(B))^2。牛牛对函数值为整数的情况很感兴趣。
现在给定整数n和m,
请帮助牛牛计算有序对(A, B)的数量,
 满足1 ≤ A ≤ n, 1 ≤ B ≤ m
而且SSR(A, B)是一个整数。

输入描述:
输入包括两个整数n和m(1 ≤ n ≤ 10^5, 1 ≤ m ≤ 10^5)

输出描述:
输出一个整数,表示满足条件的有序对对数。

输入例子1:
3 8

输出例子1:
5
*/

思路如下:

其实就是找给定范围内的数,组成对(A, B)使得 A*B为完全平方数
枚举A B
首先建立素数表
然后对于没一个A建立一个其特征
这个特征是一个整数feature=1,这么定义:
对于A的所有质因数pi若其指数为奇数,feature*=pi
为了提高一点效率这个feature应该选用
feature[A]表示A特征
map<int feature, int freq>表示在某个范围内出现这样feature的频率
注意这里的feature也最多是10^5 因为一个数A的feature<=A
若一个数的feature=1表示这个数是一个完全平方数
(注意:由于feature中素因子都是只有一次项,那么就是说不可能有A和B的feature相同,但是却奇次幂素因子却不能匹配)
那么B如果有和A同样的feature表示,A,B中那些为奇数幂的质因子可以配对成偶数
求feature的时间O(logN)
最大时间复杂度O(NlogN)

代码如下:

#include<stdio.h>
#include<iostream>
#include<vector>

#define MAX 100005

using namespace std;

//featureOfNum[num]表示num这个数的feature、
//统计这个featureOfNum可以一次性计算好范围较大的那一段,两段可以共用
int featureOfNum[MAX];
//featureToFreqMap[feature]表示feature这个特征出现的频率
//注意统计这个featueToFreqMap仅仅统计范围更小的那一段
int featureToFreqMap[MAX];

//建立素数表
vector<int> BuildPrimesTable(int n)
{
    vector<int> primes;
    bool *isNotPrime=new bool[n+1];
    isNotPrime[0]=isNotPrime[1]=true;
    for(int i=2; i<=n; i++)
        isNotPrime[i]=false;
    for(int i=2; i<=n; i++){
        if(isNotPrime[i]){
            continue;
        }
        primes.push_back(i);
        for(int j=i+i; j<=n; j+=i)
            isNotPrime[j]=true;
    }
    return primes;
}

//对num进行质因数分解然后解决,得出num中那些奇次幂的因子的积
int GetFeature(int num, vector<int>& primes)
{
    int feature=1;
    int tempNum=num;
    for(int i=0; i<primes.size(); i++){
        int prime=primes[i];
        if(tempNum<prime)
            break;
        int powCnt=0;
        while(tempNum%prime==0){
            tempNum/=prime;
            powCnt++;
        }
        //为奇次幂的乘到feature中
        if(powCnt%2)
            feature*=prime;
    }
    return feature;
}

int main()
{
    int m, n;
    scanf("%d%d", &m, &n);
    //保证m是比较小的那一段
    if(m>n)
        swap(m, n);
    //先建立好最大范围内的素数表
    vector<int> primes;
    primes=BuildPrimesTable(n);
//    //测试
//    for(int i=0; i<primes.size(); i++)
//        printf("%d ", primes[i]);
//    printf("\n");
    //建立featureOfNum和featureToFreqMap
    for(int i=1; i<=n; i++){
        int feature=GetFeature(i, primes);
//        printf("i: %d, feature: %d\n", i, feature);
        if(i<=m){
            featureToFreqMap[feature]++;
        }
        featureOfNum[i]=feature;
    }
    long long totalPairs=0;
    for(int i=1; i<=n; i++){
        int feature=featureOfNum[i];
        totalPairs+=(long long)featureToFreqMap[feature];
    }
    printf("%lld", totalPairs);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值