标签:span 容斥原理 sig stream i++ mes def long 之间
题意: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
标签:span 容斥原理 sig stream i++ mes def long 之间
原文地址:https://www.cnblogs.com/myx12345/p/10019370.html