欧拉函数(或者容斥)-HDU5514
来源:互联网 发布:淘宝怎么更改支付宝 编辑:程序博客网 时间:2024/05/21 06:24
题目
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5514
题目来源:2015沈阳区域赛,现场A的题,银牌题。
简要题意:n个青蛙在m长的环上从0开始无限跳,每只跳ai远,求所有会被青蛙跳到的格子下标之和。
数据范围:T⩽20;1⩽n⩽104;1⩽m⩽109;ai⩽109
显然很容易看出格子是否被跳和gcd(ai,m)有关。
对于任意一个gcd(ai,m),其[0,m)内的倍数一定会被跳到。
这个命题进行转化就是对于一个格子x,如果存在gcd(ai,m)∣x,那它会被跳到。
由于gcd(x,m)∣m,其规模最大为m的约数。
gcd(ai,m)∣gcd(x,m)是x被跳到的充要条件。
于是我们可以枚举m的约数g,让gcd(x,m)=g的数形成一个集合,通过gcd(ai,m)∣g的存在性来判断该集合的数是否该被加入。
如果加入的话,由欧拉函数就可以得到集合元素的和了。
比x小与之互质的数的和为φ(x)x2(注意是小,不是小于等于,小于等于要特判1,钢霸发现这个点的)。
于是结果为gφ(m/g)m/g2=φ(m/g)m2。
注意g=m的情况需要去掉,因为是[0,m)的。
实现
基本上怎么写都是过,沈阳的时候随手写了发很暴力的欧拉和枚举,都过了。
回来尝试了下分解素因数再枚举约数,结果没有快非常多。
会写欧拉的话实现这道题不是很难,还可以用容斥原理写
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <stack>#include <queue>#include <string>#include <vector>#include <set>#include <map>#define pb push_back#define mp make_pair#define all(x) (x).begin(),(x).end()#define sz(x) ((int)(x).size())#define fi first#define se secondusing namespace std;typedef long long LL;typedef vector<int> VI;typedef pair<int,int> PII;LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}// headconst int N = 1E4+5;int t, n, m, cas = 1;int a[N];LL getPhi(int m) { int phi = m; for (int i = 2; i*i <= m; i++) { if (m % i == 0) { while (m % i == 0) m /= i; phi = phi/i*(i-1); } } return m > 1 ? phi/m*(m-1) : phi;}bool ck(int x) { for (int i = 0; i < n; i++) { if (x % a[i] == 0) return true; } return false;}int main() { scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { scanf("%d", a+i); a[i] = __gcd(a[i], m); } LL ans = 0; for (int i = 1; i*i <= m; i++) { if (m % i) continue; if (ck(i)) ans += (LL)getPhi(m/i)*m/2; if (i*i == m || i == 1) continue; if (ck(m/i)) ans += (LL)getPhi(i)*m/2; } printf("Case #%d: %I64d\n", cas++, ans); } return 0;}
容斥代码
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <vector>#include <queue>#include <algorithm>#include <set>using namespace std;typedef long long LL;typedef unsigned long long ULL;const LL INF = 1e17+5;const LL MAXN = 1e6+5;const int MOD = 1e9+7;const double eps = 1e-7;const double PI = acos(-1);using namespace std;LL a[MAXN], tmp[MAXN];LL vis[MAXN], num[MAXN];///vis:标记可以走哪些因子数 num[i]:第i个因子加了几次。LL GCD(LL a, LL b){ if(b == 0) return a; return GCD(b, a%b);}int main(){ LL T; scanf("%lld",&T); for(LL cas=1; cas<=T; cas++){ LL n, m, cnt = 0; scanf("%lld%lld",&n,&m); for(LL i=1; i*i<=m; i++){ if(m%i==0){ if(i*i != m) tmp[cnt++] = m/i; tmp[cnt++] = i; } } sort(tmp, tmp+cnt); memset(vis, 0, sizeof(vis)); memset(num, 0, sizeof(num)); for(LL i=0; i<n; i++) scanf("%lld",&a[i]); for(LL i=0; i<n; i++){ LL x = GCD(a[i], m); for(LL j=0; j<cnt-1; j++)///计算到 cnt-1 就行了 if(tmp[j] % x == 0) vis[j] = 1; } LL ans = 0; /**考虑每个因子的贡献是:(m/tmp[i])*(m/tmp[i]-1)/2*tmp[i],等差数列求和 首先将因子 tmp[i] 提出来 m/tmp[i]:相当于等差数列的 a1 + an; m/tmp[i]-1: 这是等差数列的个数 **/ for(LL i=0; i<cnt-1; i++){ if(num[i] != vis[i]){ ///先计算 vis[i] - num[i] == 1 的 ans += (m/tmp[i])*(m/tmp[i]-1)/2*tmp[i]*(vis[i]-num[i]); ///cout<<"ans = "<<ans<<endl; LL tp = vis[i] - num[i]; for(LL j=i; j<cnt-1; j++) if(tmp[j] % tmp[i] == 0) num[j] += tp; } } printf("Case #%lld: %lld\n",cas,ans); } return 0;}
阅读全文
0 0
- 欧拉函数(或者容斥)-HDU5514
- hdu5514 Frogs(容斥)
- HDU5514 Frogs(GCD+欧拉函数+数论)
- hdu5514(有技巧的容斥)
- HDU5514(容斥)
- hdu5514 Frogs(容斥)
- HDU5514 Frogs 容斥原理
- 欧拉函数+容斥
- hdu5514容斥原理和群论
- HDU5514 Frogs (gcd + 容斥原理)
- HDU_1695_GCD(欧拉函数+容斥原理+DFS)
- HDU1695-GCD(数论-欧拉函数-容斥)
- hdu1695--GCD(欧拉函数+容斥原理)
- hdu4135--Co-prime(欧拉函数+容斥原理)
- HDU 1695(欧拉函数+容斥原理)
- hdu-1695 GCD(容斥原理+欧拉函数)
- hdu 1695 GCD (欧拉函数、容斥原理)
- HDU 1695 GCD(欧拉函数+容斥原理)
- iPhone 8快速充电技术简介,苹果再也不能被安卓嘲笑充电慢
- 一直用PDO,PHP中操作MYSQL数据库常用函数还记得不
- S5PV210刷机方法
- MySQL explain执行计划解读
- 剑指offer 链表题最佳解汇总 Python
- 欧拉函数(或者容斥)-HDU5514
- 学习笔记:ES6之Promise
- Linux内核进程调度
- Redis集群方案大全
- 前端性能优化+CDN优化
- datagrid控制分页js代码
- JAVA设计模式之单例模式
- Solr的安装及配置
- 极光推送服务器端代码(java服务器后台向手机端自定义推送消息)