博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 5514 题解
阅读量:4322 次
发布时间:2019-06-06

本文共 1283 字,大约阅读时间需要 4 分钟。

题意:给出n和m,代表有n只青蛙和m颗标号为0~m-1的石子,m颗石子围成一个圈,给出n个数据ai表示一只青蛙一次能跳多少步,求最终所有被青蛙踩过的石子的标号和。

1<=N<=10000,1<=m<=1e9,1<=ai<=1e9;共1~20组数据,1000MS

算法/思路:容斥原理:首先为了方便处理,将ai变为gcd(ai,m)(用数论知识可以证明结果不变),然后使用容斥原理,当然不能用2n那么多次操作的方法,于是有一个较为巧妙的方法,求出m的所有因子(约为log2m个),并从小到大排序,然后对第i个因子,依次判断每个ai是否有经过它,有则将vis[i]记为1,否则为0,并将所有num[i]初始化为0(num数组用于表示某数用过多少次),最后从小到大扫描每个因子Ai,令ans+=(vis[i]-num[i])*(Ai*(m/Ai-1)/2),并扫描所有比Ai大的因子Ak,若Ak是Ai的倍数,则num[k]+=(vis[i]-num[i]),这样显然每个数最终只使用一次(相当于容斥时直接判断数被重复利用了几次)。算法复杂度O(log2m(n+log2m))

 

#include
#include
#include
#include
#include
#include
using namespace std; const int maxn=10005; int t,n,m,sq,tot;int a[maxn+5];vector
vis,num;vector
x;long long ans; int gcd(int x,int y){ if (y==0) return x;else return gcd(y,x%y);} void init(){ x.clear();tot=1;ans=0; vis.clear();num.clear(); scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",&a[i]);} int main(){ scanf("%d",&t); for (int q=1;q<=t;++q){ init(); sq=floor(sqrt(m)+0.5); x.push_back(1);//故初始化tot=1; for (int i=2;i<=sq;++i) if (m%i==0){ x.push_back(i);++tot; if (m/i==i) continue; x.push_back(m/i);++tot; } vis.resize(tot,0);num.resize(tot,0); //for (int i=0;i

 

转载于:https://www.cnblogs.com/terra/p/7018861.html

你可能感兴趣的文章
Vert.x 之 HelloWorld
查看>>
太阳能路灯项目背景知识
查看>>
Objec类和final关键字的用法
查看>>
打开matlab遗传算法工具箱的方法
查看>>
Ajax制作智能提示搜索
查看>>
打赏页面
查看>>
JAVA之线程同步的三种方法
查看>>
OOP之属性继承和方法继承
查看>>
PostgreSQL调用函数
查看>>
ASP.NET MVC+EF框架+EasyUI实现权限管理(附源码)
查看>>
sitecore系统教程之体验编辑器中创建一个项目
查看>>
socket笔记
查看>>
Java 概述及安装使用
查看>>
helloworld
查看>>
港交所OMD-C对接笔记
查看>>
线程安全问题了解一下
查看>>
转:IPv4的地址真的用光了吗
查看>>
java rmi远程方法调用实例
查看>>
Linux设置环境变量小结
查看>>
syslog()用法
查看>>