描述
老师让n(1<=n<=100000)个小朋友围成一个圈,第k名同学和第k+1以及第k-1名同学相邻,1号同学和n号同学相邻,老师在一个包里放了很多写有数字的纸条,可能多个个纸条上的数字是相同的,并且数字num的范围是1<=num<=1000000。接下来每一位同学i从包里抽出一张纸条Ai,每位同学都走一圈,同时拍打能整除纸条上数字的同学后背,然后走回到自己的位置上。要求你计算出每位同学总共拍打了多少同学的后背。
输入
第一行包含一个整数n,接下来的n行,每行输入一个整数Ai。
输出
输出共有n行,每行一个数字,表示该同学拍打其他同学的数量。
输入样例 1
5 2 1 2 3 4
输出样例 1
2 0 2 1 3
思路:
详见注释(皮一下很开心)
代码:
#include<bits/stdc++.h>
using namespace std;
int a[10000005];
int n,mx=-100;
int b[1000005];
int cnt[1000005];
void get_factor(){
for (int i = 1; i <= 1000000; i++){//题目中说明数字不超过100w
if(!b[i]) continue;//数字必须存在,不存在则跳过
for (int j = 1; j <= 1000000 / i; j++){
// b[i*j]为真,表示i这个数字的j倍也是存在的,那么显然i*j能整除i,
//所以我们要统计i*j这个数字能被整除多少次时就要把i这个数字出现的次数累加上去
//i这个数字出现的次数就是b[i]
//我们用cnt[i*j] 来累计i*j这个数字被整除的次数,所以有cnt[i*j]+=b[i];
if(b[i*j]) cnt[i*j]+=b[i];
//这个地方很关键,因为j是从1开始的,所以要把自己整除自己的那一次减掉
//但是j初始化是必须从1而不能从2开始,因为i这个数字有可能出现了多次
//其实下面这一句可以不要,然后在输出答案的地方减1,及输出cnt[a[i]]-1就可以了。
if(i*j==i) cnt[i]--;
}
}
}
int main(){
scanf("%d",&n);//输入n个人
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);//输入每个人手中的数字
b[a[i]]++;//因为每个人手中的数字可能重复,所以用桶算法
}
get_factor();
for(int i=1;i<=n;i++)
cout<<cnt[a[i]]<<endl;
return 0;
}
原文:https://www.cnblogs.com/mysh/p/11291551.html