#10199. 「一本通 6.2 练习 2」轻拍牛头 用唯一分解定理求因子值

题目:

今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏。贝茜让 N 头奶牛坐成一个圈。除了 1 号与 N号奶牛外,i 号奶牛与 i − 1 号和 i + 1 号奶牛相邻,N 号奶牛与 1 号奶牛相邻。农夫约翰用很多纸条装满了一个桶,每一张包含了一个 1 到 10^6 的数字。接着每一头奶牛 i 从桶中取出一张纸条 Ai ,每头奶牛轮流走一圈,同时拍打所有编号能整除在纸条上的数字的牛的头,然后走回到原来的位置。奶牛们想让你帮他们计算,对于每头奶牛,它需要拍多少头奶牛的头?

输入格式
第一行包含一个整数 N;
接下来第二到第 N + 1  行每行包含一个整数 Ai  。

输出格式
第一到第 N 行,第 i 行的输出表示第 i  头奶牛要拍打的牛数量。

样例
样例输入
5
2
1
2
3
4

样例输出
2
0
2
1
3

数据范围与提示
对于全部数据,1 ≤ N ≤ 10^5

思路:

此题主要是怎样快速求每个数的因子
这时候就用到唯一分解定理了,那么怎么用呢?
首先举个例子:72
72的因子:1 2 3 4 6 8 9 12 18 24 36 72
用唯一分解定理分解72之后得:2^3*3^2
即:2 2 2 3 3
质数为2组成:2 4 8
质数为3组成:3 9
用后面每个质数组的因子去乘以前面的因子放在数组后面即可
2 4 8
用3去乘得6 12 24把这些数放在数组后面并把3也放进去
然后用9去乘得18 36 72把这些数放在数组后面并把9也放进去
然后数组就变成 2 4 8 6 12 24 3 18 36 72
最后再把1放进去就OK了

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
typedef long long ll;
int book[N],a[N];
bool vis[N];
int x[N],y[N];
int tag[N],cnt;
int fg[N];
void su()//素数打表So easy
{
    cnt=0;
    vis[1]=true;
    for(int i=2;i<N;i++){
        if(!vis[i]){
            tag[cnt++]=i;
            for(int j=i*2;j<N;j+=i)vis[j]=true;
        }
    }
}
int main()
{
    su();
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        book[a[i]]++;//把相同的数统计一下
    }
    memset(fg,0,sizeof(fg));
    for(int i=1;i<=n;i++){
        if(fg[a[i]])continue;//计算过的数不用再算了
        int k=a[i],z=0;
        for(int j=0;j<cnt&&tag[j]*tag[j]<=k;j++)//唯一分解定理
        {
            if(k%tag[j]==0){
                int t=0;
                int mi=tag[j];
                while(k%tag[j]==0){
                    x[t++]=mi;
                    k/=tag[j];
                    mi*=tag[j];
                }
                if(z==0)
                {
                    for(int w=0;w<t;w++)
                        y[z++]=x[w];
                }
                else {
                    int q=z;
                    for(int w=0;w<t;w++)
                    {
                        y[z++]=x[w];
                        for(int p=0;p<q;p++){
                            y[z++]=x[w]*y[p];
                        }
                    }
                }
            }
        }
        if(k>1){
            int q=z;
            y[z++]=k;
            for(int j=0;j<q;j++)
                y[z++]=y[j]*k;
        }
        y[z]=1;
        int sum=0;
        for(int j=0;j<=z;j++)
        if(y[j]==a[i])sum+=book[y[j]]-1;
        else sum+=book[y[j]];
        fg[a[i]]=sum;
    }
    for(int i=1;i<=n;i++)
        printf("%d\n",fg[a[i]]);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值