HDU-5514 Frogs (容斥)

 题目链接:Frogs

题意:有n只青蛙和m块石头(石头编号为0 - n-1)排成一个环,刚开始每只青蛙都在标号为0的石头上。每只青蛙每次跳a[i]的距离,但凡被青蛙经过的石头都会被占领,求这m块石头中所有被占领过的石头的编号和。

题解:首先,可以发现每只青蛙跳过的石头的标号是gcd(a[i] , M)的倍数。所以把每只青蛙的gcd求出来后就是一个容斥了,容斥主要看代码领悟。如果出现了一个x = gcd(ai,m),那么所有x的倍数的因数都算是出现过了,在计算的时候如果把x的倍数都加了k遍,那么就要把pk的倍数减去k遍。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define fi first
 4 #define se second
 5 typedef long long LL;
 6 typedef pair<LL,int> P;
 7 const int MAX_N = 1e5+7;
 8 const LL inf = 0x3f3f3f3f3f3f3f3f;
 9 LL N,M,T,S;
10 int vis[MAX_N];
11 LL pi[MAX_N];
12 int num;
13 LL gcd(LL a,LL b){
14     return b == 0?a : gcd(b,a%b);
15 }
16 void init(){
17     num = 0;
18     pi[num ++ ] = 1;
19     for(int i=2;i*i<=M;i++){
20         if(M%i == 0){
21             if(i == M/i){
22                 pi[num++] = i;
23             }
24             else{
25                 pi[num++] = i;
26                 pi[num++] = M/i;
27             }
28         }
29     }
30     sort(pi,pi+num);
31     memset(vis,0,sizeof(vis));
32 }
33 int main(){
34     cin>>T;
35     int out = 0;
36     while(T--){
37         out ++;
38         scanf("%lld%lld",&N,&M);
39         init();
40         for(int i=0;i<N;i++){
41             LL t;
42             scanf("%lld",&t);
43             LL x = gcd(t,M);
44             for(int j=0;j<num;j++){
45                 if(pi[j]%x == 0){
46                     vis[j] = 1;
47                 }
48             }
49         }
50 
51         LL ans = 0;
52         for(int i=0;i<num;i++){
53             if(vis[i] != 0){
54                 LL t = pi[i];
55                 LL n = (M-1) / t;
56                 ans +=  (t+n*t)*n/2*vis[i];
57                 for(int j = i+1;j<num;j++)
58                 {
59                     if(pi[j] % pi[i] == 0){
60                         vis[j] -= vis[i];
61                     }
62 
63                 }
64 
65             }
66         }
67         printf("Case #%d: %lld\n",out,ans);
68     }
69     return 0;
70 }

 

转载于:https://www.cnblogs.com/doggod/p/9748314.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值