1. 程式人生 > >【HDOJ5514】Frogs(容斥原理)

【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\n",v,ans); 57 } 58 return 0; 59 } 60