【HDOJ5514】Frogs(容斥原理)

题意:n个青蛙在一个有m个节点的圆上跳,m个节点的标号为0-m-1,每只青蛙每次跳的节点数给出,让求n只青蛙所跳位置标号之和

n<=1e4,m<=1e9,a[i]<=1e9

思路:由裴蜀定理可知该问题等价于[0,m-1]能被至少一个gcd(m,a[i])整除的数字之和

因为n过大,考虑与m的因子个数相关的算法,因子个数<=200

做因子之间的容斥,每一个因子a[i]的贡献t=贡献次数*a[i]*(m/a[i]-1)*(m/a[i])/2

后面部分是一个等差数列

算完每一个因子的贡献之后再维护其倍数因子的贡献

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 typedef long long ll;
 7 typedef unsigned long long ull;
 8 using namespace std;
 9 #define N   40000 
10 #define M   32
11 #define oo  10000000
12 #define MOD 105225319
13 
14 int a[N],vis[N];
15 
16 int gcd(int x,int y)
17 {
18     if(!y) return x;
19     return gcd(y,x%y);
20 }
21 
22 int main()
23 { 
24      int cas;
25      scanf("%d",&cas);
26      for(int v=1;v<=cas;v++)
27      {
28          int n,m;
29          scanf("%d%d",&n,&m);
30          memset(vis,0,sizeof(vis));
31          int tot=0;
32          for(int i=1;i*i<=m;i++)
33           if(m%i==0)
34           {
35               a[++tot]=i;
36               if(i*i!=m) a[++tot]=m/i;
37           }
38          sort(a+1,a+tot+1);
39         for(int i=1;i<=n;i++)
40         {
41             int x;
42             scanf("%d",&x);
43             int t=gcd(m,x);
44             for(int j=1;j<=tot;j++)
45              if(a[j]%t==0) vis[j]=1;
46         }
47         ll ans=0;
48         for(int i=1;i<=tot;i++)
49          if(vis[i])
50          {
51              ll t=m/a[i];
52              ans+=(ll)a[i]*t*(t-1)/2*vis[i];
53              for(int j=i+1;j<=tot;j++)
54               if(a[j]%a[i]==0) vis[j]-=vis[i];
55          }
56         printf("Case #%d: %I64d
",v,ans);
57     }
58     return 0;
59 }
60     
原文地址:https://www.cnblogs.com/myx12345/p/10019370.html