数学基础——质数(轻拍牛头)

问题描述

原题来自:USACO 2008 Dec. Silver

今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏。

贝茜让 N头奶牛坐成一个圈。除了 1 号与 N 号奶牛外,i 号奶牛与 i−1号和 i+1 号奶牛相邻,N 号奶牛与 1号奶牛相邻。农夫约翰用很多纸条装满了一个桶,每一张包含了一个 1 到 10 6的数字。

接着每一头奶牛 i 从桶中取出一张纸条 Ai ,每头奶牛轮流走一圈,同时拍打所有「编号是 Ai 的约数」的牛,然后走回到原来的位置。牛们希望你帮助他们确定,每一头奶牛需要拍打的牛。

输入

第一行包含一个整数 N;

接下来第二到第 N+1 行每行包含一个整数 Ai 。

输出

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

样例输入

5

2

1

2

3

4

样例输出

2

0

2

1

3

提示

数据范围与提示:

对于全部数据,1≤N≤105 。

问题分析

看完题目第一个想法是枚举的n2,之后发现完全可以用桶来记元素,然后通过类似于筛法求素数的方法,求出某一个元素的倍数的个数,-1即为答案。

算法设计

先读入统计一遍所有的数,之后因为每个数只会被比他小的因数除去,所以枚举每个数的倍数。最好把一样的数用数组保存,不然可能一个个筛会超时。然后就是要注意j要从i而不是2i开始枚举,因为可能存在相同的数字,最后给ans减1就好了。

代码

#include<cstdio>

#include<algorithm>

using namespace std;

const int N=1e6+10;

int n,a[N],cnt[N],ans[N],maxn;

int main()

{

scanf("%d",&n);

       for(int i=1;i<=n;i++)

{

scanf("%d",&a[i]);

maxn=max(maxn,a[i]);

cnt[a[i]]++;

}

       for(int i=1;i<=maxn;i++)

{

if(cnt[i])

{

for(int j=i;j<=maxn;j+=i)

ans[j]+=cnt[i];

}

}

       for(int i=1;i<=n;i++)

printf("%d\n",ans[a[i]]-1);

       return 0;

}

算法复杂度分析

       使用枚举法的算法复杂度为O(n2);利用上述的筛选法,并且将相同的数字合并能够到一个数组中一起计算,算法复杂度下降到O(nloga)。

猜你喜欢

转载自blog.csdn.net/zxy2016011117/article/details/86489786