icodelab 另一个转圈游戏

描述

老师让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;
} 

 

 

 

猜你喜欢

转载自www.cnblogs.com/mysh/p/11291551.html