标签:没有 ref 石头 clu through while http 分析 sort
有n只青蛙,有m块石头,编号为0~m-1,第i只青蛙每次可以跳$a_i$, 刚开始都在0,问,青蛙总共可以跳到的石头之和为多少。其中$t≤20$,$1≤n≤10^4$,$1≤m≤10^9$,$1≤a_i≤10^9$.
分析
根据裴蜀定理知,对于一个有n个点的环,每个循环节的长度为n/gcd(n, k),k为每次走的步数。所以青蛙可以达到的石头编号肯定是$gcd(m,a_i)$的倍数,相当于真正步长为$gcd(m,a_i)$.
当然要容斥一下,不就是奇加偶减吗,枚举所有的项有$2^n$个($n$是gcd的个数),还要加剪枝,如果当前的lcm是gcd[i]的倍数,那么可以不继续容斥下去(也就是对答案没有贡献).
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 5 typedef long long ll; 6 const int maxn = 100000 + 10; 7 ll n, m; 8 ll fac[maxn], cnt, sum; 9 10 ll gcd(ll a, ll b) 11 { 12 return b == 0 ? a : gcd(b, a % b); 13 } 14 ll lcm(ll a, ll b) 15 { 16 return a * b / gcd(a, b); 17 } 18 19 void dfs(int pos, ll tlcm, int sz) 20 { 21 //printf("pos:%d tlcm:%lld sz:%d\n", pos, tlcm, sz); 22 if(tlcm >= m) return; 23 if(pos == cnt) 24 { 25 if(sz == 0) return; 26 if(sz & 1) 27 { 28 ll tmp = (m-1) / tlcm; 29 sum += tmp * (tmp+1) * tlcm / 2; //o tlcm 2*tlcm... tmp*tlcm 奇加偶减 30 } 31 else 32 { 33 ll tmp = (m-1) / tlcm; 34 sum -= tmp * (tmp+1) * tlcm / 2; //o tlcm 2*tlcm... tmp*tlcm 35 } 36 return; 37 } 38 if(tlcm % fac[pos] == 0) return; 39 dfs(pos+1, tlcm, sz); 40 dfs(pos+1, lcm(tlcm, fac[pos]), sz+1); 41 } 42 43 int main() 44 { 45 int T, kase = 0; 46 scanf("%d", &T); 47 while(T--) 48 { 49 scanf("%lld%lld", &n, &m); 50 bool flag= false; 51 for(int i = 0;i < n;i++) 52 { 53 ll tmp; 54 scanf("%lld", &tmp); 55 fac[i] = gcd(tmp, m); 56 if(fac[i] == 1) flag = true; 57 } 58 printf("Case #%d: ", ++kase); 59 if(flag) 60 { 61 printf("%lld\n", (m-1) * m / 2); 62 } 63 else 64 { 65 sort(fac, fac+n); 66 cnt = unique(fac, fac+n) - fac; 67 sum = 0; 68 dfs(0, 1, 0); 69 printf("%lld\n", sum); 70 } 71 } 72 return 0; 73 }
网上更多的解法是分析m的因子,求贡献。(然而没有看懂)
参考链接:http://www.acmtime.com/?p=864
标签:没有 ref 石头 clu through while http 分析 sort
原文地址:https://www.cnblogs.com/lfri/p/11181617.html