2015 沈阳 Frogs

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5514

这道题目是一个典型的容斥定理类题目,通过巧妙的运用gcd可以获取青蛙的真实无限步骤后的最小步长。例如12个石子围成一圈,青蛙每次跳10步相当于

石子编号 0 1 2 3 4 5 6 7 8 9 10 11
第i步位置6 0 5 0 4 0 3 0 2 0 1(7) 0

那么他与实际每次只跳gcd(12,10)效果是一样的。

下面我们考虑m是1e9范围存不下,就只能用容斥定理进行解题。对于每一只青蛙,可以在O(1)时间内计算到达石子编号之和,但会产生两只青蛙都跳过同一个点的情况。这样再减去就可以了。当时做的时候调了半天,最后发现其实不管加还是减其实都一定是m的约数,因为是用gcd算出来的。同时这道题目算哪些点访问过只开一个数组会有些力不从心,当时调很久都没能调出来。

看了别人的才明白过来,其实只需要开两个数组对应visit数组(c)和num数组(d)每次算visit-num就是当前因子应该加减的遍数,由于算了当前的那么对于后面每一个可以被当前因子整除的num都应当调整,让后续不再多算。比如第一个样例gcd分别是2和3,那么算2的时候回把6加进ans,算3的时候又会把6加进ans,6的visit应当是1,但num却变成2,应当减去。而4和8在算2的时候算了一遍,算3的时候没有多算,那么visit=num意味着已经正常算过,不需要重复。

我之前开一个数组不可以的原因我想是因为我没有办法区分当前数据是否应当计算,只是单纯自减无法适应多层次的调整,因为比如因数较多的时候如果有2 3 4 6 12那么在算2和3会把6和12对应多算,但在处理6的时候12多算的处理已经解决,而我却无法合适的处理(自减已经不对)。或许大家有处理的好方法,期待留言。

上面的方法是一种加多则减的方法,我又看到一种更加巧妙的方法,分享给大家。原文描述有些不好,理解花了些时间,但方法真的好,是在加的时候做处理从而直接就不会加重复。我们考虑24因数为2 3 4 6 8 12的情况,对于每一个因数i,如果因数为至少一个gcd的值的倍数那么就加上所有与m/i互质的数的i倍。

对于如果有一个gcd=4,那么就有三个因数与之成倍数4,8,12。我们计算4的时候只加上与6互质的数的4倍也就是1*4和5*4对应的4和20,计算8的时候只加上与8互质的数的8倍也就是1*8和3*8对应8和24,同理算12的时候只加上了12。这样算4的时候就不会产生重复加的情况,也就不需要再想如何去减。

我们再考虑12的因数对应2,3,4,6有若干个gcd=2,3,6的情况,对于2算了与6互质的数的两倍,也就是1*2=2,5*2=10;而3算了1*3=3,3*3=9;6算了1*6=6。这样看似6可能被算多次,实际却只算了一次。也不会因为2,3,6都是6的公因子而计算多遍,因为上面说过至少一个就计算他,同时也只会计算一遍。算互质的数也很好算计算φ(m/i)*(m/i)/2就是互质数的和,再乘以i就得到结果。下面是两种思路的实现代码。

using namespace std;
#include <bits/stdc++.h>
#define int long long
int a[10000005];int n,m;
int gcd (int a,int b)
{return b==0?a:gcd(b,a%b);
}
int oula (int n)
{int ans=n;for (int i=2;i*i<=n;i++){if (n%i==0){ans=ans/i*(i-1);while (n%i==0) n/=i;}}if (n!=1) ans=ans/n*(n-1);return ans;
}
bool check (int x)
{for (int i=0;i<n;i++){if (x%a[i]==0)return true;}return false;
}
signed main (void)
{int _;cin>>_;int Case=0;while (_--){cin>>n>>m;bool prime=false;int ans=0;for (int i=0;i<n;i++){int x;cin>>x;a[i]=gcd(x,m);if (a[i]==1) prime=true;}if (prime) {ans=(m-1)*m/2;}else {for (int i=2;i*i<=m;i++){if (m%i==0){if (check(i)) ans+=oula(m/i)*m/2;if (i*i!=m&&check(m/i)) ans+=oula(i)*m/2;}}}printf("Case #%d: %lld\n", ++Case, ans);}
}
/*
本代码参考:
https://blog.csdn.net/Cassie_zkq/article/details/101560583
*/
using namespace std;
#include <bits/stdc++.h>
#define int long long
int a[10000005];
int b[10000005];
int c[10000005];
int d[10000005];
int n,m;
int gcd (int a,int b)
{return b==0?a:gcd(b,a%b);
}
signed main (void)
{int _;cin>>_;int Case=0;while (_--){cin>>n>>m;bool prime=false;int ans=0,cnt=0;for (int i=0;i<n;i++){cin>>a[i];if (gcd(a[i],m)==1) prime=true;}if (prime) {ans=(m-1)*m/2;}else {for (int i=2;i*i<=m;i++){if (m%i==0){b[cnt++]=i;b[cnt++]=m/i;}}sort(b,b+cnt);for (int i=0;i<n;i++){for (int j=0;j<cnt;j++){if (b[j]%gcd(a[i],m)==0){c[j]=1;}}}//for (int i=0;i<cnt;i++) cout<<c[i]<<' ';cout<<'\n'; //for (int i=0;i<cnt;i++) cout<<b[i]<<' ';cout<<'\n'; for (int j=0;j<cnt;j++){if (c[j]!=d[j]){ans+=m*(m/b[j]-1)/2*(c[j]-d[j]);//cout<<j<<'+'<<m*(m/b[j]-1)/2*(c[j]-d[j])<<'\n';for (int i=j+1;i<cnt;i++){if (b[i]%b[j]==0){d[i]+=c[j]-d[j];}}}}//for (int i=0;i<cnt;i++) cout<<d[i]<<' ';cout<<'\n'; for (int i=0;i<cnt;i++) d[i]=c[i]=b[i]=0;}printf("Case #%d: %lld\n", ++Case, ans);}
}

2015 沈阳 Frogs相关推荐

  1. 记2015沈阳区域赛

    前记 基本确定了要去沈阳和上海打区域赛,听说苏大cp也会沈阳,于是我们的最终目标变为了压苏大. 周五 下午一点左右的飞机,本来想要早上赶概率论作业然后交到学校去,结果睡晚了,干脆就早点去了机场,然后大 ...

  2. 【2015沈阳现场A】

    题意:求个一个n 求2^n-1能被7整除得有多少个,(1,2,....n) 简单得同余方程 #include<bits/stdc++.h> #include <iostream> ...

  3. hdu5461(2015沈阳网络赛L题)

    题意: 给出一个数列,我们要在这里找出两个数,使得题意中那个表达式最大. 思路: 排两个序就好了啊,看代码一下就懂了. 代码: #include <cstdio> #include < ...

  4. hdu5452(2015沈阳网络赛C题)

    题意: 给出一个无向图和一个此图的生成树,让我们求一个本图的最小割边集,割边集只包括生成树中的一条边,让割边集的边数最少,输出数目. 思路: 并查集+暴力. 代码: #include<cstdi ...

  5. hdu5455(2015沈阳网络赛F题)

    题意: 给出一个串,问用题中定义的那些串来组成这个串最少要用多少个. 思路: 没啥说的,注意一下输入的串中可能出现除了c和f的字母. 代码: #include<cstdio> #inclu ...

  6. hdu5459(2015沈阳网络赛J题)

    题意: 给出一个类似于斐波那契数组的字符串的定义,给出一个n,让求第n个串中任意两个c的距离的和. 思路: 我们用了三个小时找规律,最后发现是递推... 代码: #include <cstdio ...

  7. 2015 ACM/ICPC Asia Regional Shenyang Online题解

    以下所有AC题解程序来自"仙客传奇"团队. AC题数:7/13 ABCFGJL A. Traversal AC的C++语言程序: #include <bits/stdc++. ...

  8. python删除列表元素delete_Python3 tkinter基础 Listbox delete 删除单个、所有元素

    Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda : 4.5.11 typesetting : Markdown ...

  9. HDU 5454 Excited Database (2015年沈阳赛区网络赛E题)

    1.题目描述:点击打开链接 2.解题思路:本题利用线段树解决,根据题意,我们需要建立两棵线段树,分别维护主对角线,副对角线.每个线段树的结点需要维护sum,sumL,sumR,其中,sum表示当前区间 ...

  10. Frogs - HDU5514

    Frogs - HDU5514 icpc沈阳2015的题目. 容斥原理和数论的应用. 题目大意为给你一个数组 a[i]a[i]a[i](a[i]a[i]a[i] 即为第 iii 只青蛙的步长) 和若干 ...

最新文章

  1. VS Code配置PHP XDebug
  2. MCSE2003学习之三
  3. pandas计算特征与所有数值特征的相关性并排序可视化:包含pearson、spearman、kendall
  4. wavelet tutorial
  5. centos6.5下安装python3安装、python3虚拟环境创建venv
  6. 【分布式计算】分布式日志导入工具-Flume
  7. AtCoder AGC037D Sorting a Grid (二分图匹配)
  8. c语言做一个抽奖小程序,小程序插件使用- 抽奖助手
  9. 【蓝桥杯单片机】定时器和中断
  10. java 监听者模式有啥用,监听者模式在系统中的应用 —— 事件总线
  11. UML--行为图(状态图、活动图)
  12. 计算机组成原理学习-哈工大《计算机组成原理》第一章
  13. c语言求m n最小公倍数,最大公因数和最小公倍数的求法 求mn的最大公约数C语言...
  14. OJ期末刷题 问题 B: 求三角形面积-gyy
  15. 7款经典的MySQL客户端软件
  16. AudioTrack 分析
  17. Python开源指南
  18. CF197D Infinite Maze 解题报告
  19. 杰克马,请问有钱就是好人吗?
  20. Morto蠕虫病毒分析报告

热门文章

  1. IT人力外包越来越流行的原因剖析
  2. 许小年:企业家精神的衰落与重振
  3. 太厉害了,阿里大牛把Java服务端做成一张超全的知识微缩地图
  4. 厉害了!28岁程序员期权过亿,彪悍从字节退休!
  5. 面向对象设计的新视角
  6. 深度学习分类常见评价指标:accuracy recall precision specificity sensitivity AUC ROC 曲线
  7. Windows 11正式版来了!一文带你免费升级、镜像下载、最低系统要求
  8. 分享一个Java和Android学习视频
  9. The content of element type mapper must match (cache-ref|cache|resultMap*|parameterMap*|sql*|inse
  10. leetcode1114. 按序打印 靡不有初,鲜克有终,小白加油加油加油