gym 101982 B题 Coprime Integers
题目链接:https://codeforces.com/gym/101982/attachments
贴一张图吧:

题目意思就是给出四个数字,a,b,c,d,分别代表两个区间[a,b],[c,d],从这两个区间里面分别拿一个数字组成(x,y),问x和y互质的组合有多少种。
这道题目好像要用莫比乌斯反演,但是目前没有了解过这个知识点,后续会补上,我用的是打表+容斥定理做的,相比于上一种方法,耗费的时间可能会多很多。我亲测是600到800ms,所以还是很有必要学莫比乌斯反演的。
接下来讲我的思路:两个区间里面所有的组合数是(b-a+1)*(d-c+1)种,我可以先算出不互质的组合的个数,再用总数减去它得到互质的组合数。
首先,假设我要算所有gcd(x,y)=2的组合数,那么在区间[a,b]里面,素因子含有2的数字个数是b/2-(a-1)/2这么多个,在区间[c,d]里面含有2这个素因子的数字的个数是d/2-(c-1)/2这么多。这两个数字相乘就是两个区间中gcd(x,y)=2的组合数字。
假如我们遍历计算1到10000000里面所有的素数(大概660000多一点),那么就会出现重复计算的情况,假如我gcd(x,y)=2和gcd(x,y)=3的情况都计算了一边,那么gcd(x,y)=6的情况就计算了两遍,那么我们就要再减去gcd(x,y)=6的情况的组合数。
这就要用到容斥定理(奇加偶减),假如一个数字n,它不同的素因子有奇数个,那么就加,如果是偶数个就减,并且它某一个素因子个数不能大于1个(6=2*3,它的素因子有2和3,素因子2有且只有一个,素因子3有且只有一个,那么这个数字我们是要计算的,另一个数字12=2*2*3,它的素因子2有2个,那么我们就不用计算它,因为它已经包含在(gcd(x,y)=2)的数量+(gcd(x,y)=3)的数量-(gcd(x,y)=6)里面了)。
那么我们现在就要先打表把所有类似于6(2*3),10(2*5),30(2*3*5),这种相同素因子只有一个的数筛出来(大概6000000个,所以花费时间有点多),然后遍历计算就可以了。
这个打表的过程可以在我们线性筛素数的过程中做到,所以这个打表是线性的。
这里面num[i]代表数字i有多少个不同的素数,例如num[30]=3,(30=2*3*5)。
flag[i]表示数字i是不是所有素数有且只有一个,如果flag[i]=true,那么这个i就是我们要找的数字。数组ok就是把这些数字存起来,等下遍历数组ok就可以了。
打表代码:
void init(){
memset(vis,,sizeof(vis));
memset(flag,false,sizeof(flag));
cnt=;//记录素数个数
cc=;//计录我们要找的数组个数
for(int i=;i<maxn;i++){
if(vis[i]==){
prime[cnt++]=i;//是一个素数
num[i]=; //不同的素因子是有它自己一个,复制为1
ok[cc++]=i; //保存在ok数组中
flag[i]=true; //标记这个数字是我们要找的
}
for(int j=;j<cnt&&(i*prime[j]<maxn);j++){
vis[prime[j]*i]=true;
if((i%prime[j])!=)//在这之前我们已经知道了num[i],只要i不被prime[j]整除,那么prime[j]*i这个数字不同素因子个数就是num[i]+1
num[prime[j]*i]=num[i]+;
if(flag[i]==&&(i%prime[j])){//假如flag[i]=true,说明i是我们要找的数字,并且i%prime[j]非0,那么prime[j]*i也是我们要找的数字
ok[cc++]=i*prime[j];
flag[i*prime[j]]=true;
}
if(i%prime[j]==)
break;
}
}
}
完整代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 10000005
int prime[maxn],vis[maxn],num[maxn],ok[maxn],flag[maxn];
int n,m,k,t,cnt,cc;
void init(){
memset(vis,,sizeof(vis));
memset(flag,false,sizeof(flag));
cnt=;//记录素数个数
cc=;//计录我们要找的数组个数
for(int i=;i<maxn;i++){
if(vis[i]==){
prime[cnt++]=i;//是一个素数
num[i]=; //不同的素因子是有它自己一个,复制为1
ok[cc++]=i; //保存在ok数组中
flag[i]=true; //标记这个数字是我们要找的
}
for(int j=;j<cnt&&(i*prime[j]<maxn);j++){
vis[prime[j]*i]=true;
if((i%prime[j])!=)//在这之前我们已经知道了num[i],只要i不被prime[j]整除,那么prime[j]*i这个数字不同素因子个数就是num[i]+1
num[prime[j]*i]=num[i]+;
if(flag[i]==&&(i%prime[j])){//假如flag[i]=true,说明i是我们要找的数字,并且i%prime[j]非0,那么prime[j]*i也是我们要找的数字
ok[cc++]=i*prime[j];
flag[i*prime[j]]=true;
}
if(i%prime[j]==)
break;
}
}
}
int main()
{
int a,b,c,d;
init();
sort(ok,ok+cc);
while(scanf("%d%d%d%d",&a,&b,&c,&d)!=EOF){
LL ans=;
int maxx=min(b,d);//记录一下两个,区间最小的右边界,可有可无吧 ,好像影响不大
for(int i=;i<cc&&ok[i]<=maxx;i++){
int now=ok[i];
if(num[now]%){//计数加 ,注意答案非常大,要用long long
ans+=(LL)(b/now-(a-)/now)*(d/now-(c-)/now);
}else{//偶数减
ans-=(LL)(b/now-(a-)/now)*(d/now-(c-)/now);
}
}
printf("%lld\n",(LL)(b-a+)*(d-c+)-ans);
}
return ;
}
待补充。。。。。。
来补充了,额,请看下面大佬介绍莫比乌斯反演,完......
补充:https://www.cnblogs.com/chenyang920/p/4811995.html
gym 101982 B题 Coprime Integers的更多相关文章
- Gym - 101982B Coprime Integers (莫比乌斯反演)
题目链接:http://codeforces.com/gym/101982/attachments 题目大意:有区间[a,b]和区间[c,d],求gcd(x,y)=1,其中x属于[a,b],y属于[c ...
- Gym - 101982B 2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) B. Coprime Integers Mobius+容斥 ab间gcd(x,y)=1的对数
题面 题意:给你 abcd(1e7),求a<=x<=b,c<=y<=d的,gcd(x,y)=1的数量 题解:经典题目,求从1的到n中选x,从1到m中选y的,gcd(x,y)=k ...
- 莫比乌斯反演第二弹 入门 Coprime Integers Gym - 101982B
题目链接:https://cn.vjudge.net/problem/Gym-101982B 题目大意: 给你(a,b)和(c,d)这两个区间,然后问你这两个区间中互素的对数是多少. 具体思路:和我上 ...
- Gym - 100221D 一题一直没过的dfs,,应该是纯手动码?
不写了,10年以后再回来写. http://codeforces.com/gym/100221/attachments H题
- codeforces GYM 100971F 公式题或者三分
F. Two Points time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...
- Gym - 100676E —— 基础题
题目链接:https://odzkskevi.qnssl.com/1110bec98ca57b5ce6aec79b210d2849?v=1490453767 题解: 这种方法大概跟离散化扯上点关系:首 ...
- Gym - 101982F Rectangles (扫描线+线段树)
链接:http://codeforces.com/gym/101982/attachments 思路: 问被覆盖次数为奇数次的矩阵的面积并 扫描线求矩阵面积并我们是上界赋为-1,下界赋为1,因为要求覆 ...
- codeforces Gym 100735 D、E、G、H、I
http://codeforces.com/gym/100735 D题 直接暴力枚举 感觉这道题数据有点问题 为什么要先排下序才能过?不懂.. #include <stdio.h> #in ...
- Gym - 101982F 扫描线+线段树
题目链接:https://codeforces.com/gym/101982/attachments 要你求覆盖奇数次的矩形面积并,每次更新时减去原先的值即可实现奇数次有效,下推时为保证线段长度不变左 ...
随机推荐
- CF963D Frequency of String
https://codeforces.com/problemset/problem/123/D 题目大意 给一个字符串 \(s\),每次询问一个字符串 \(m_i\) 和一个正整数 \(k_i\),问 ...
- 我的第二本译作《精通OpenStack》上架啦:前言、目录和样章
1. 前言 今天,随着新功能和子项目的增加,OpenStack已成为一个不断扩展的大型开源项目.随着数以百计大型企业采用并不断为OpenStack生态系统做出贡献,OpenStack必将成为下一代私有 ...
- go语言学习--string、int、int64互相转换,字符串的截取,数组和字符串的转换
下面总结了go中常用的转换 #string到int int,err:=strconv.Atoi(string) #string到int64 int64, err := strconv.ParseInt ...
- Ajax异步请求阻塞情况的解决办法(asp.net MVC Session锁的问题)
讨论今天这个问题之前,我们先来看下浏览器公布的资源并发数限制个数,如下图 不难看出,目前主流浏览器支持都是最多6个并发 需要注意的是,浏览器的并发请求数目限制是针对同一域名的 意即,同一时间针对同一域 ...
- Jquery 正则式验证
// 验证中文名称 function isChinaName(name) { var pattern = /^[\u4E00-\u9FA5]{1,6}$/; return pattern.test(n ...
- nginx+多个tomcat
学习nginx的时候遇到的问题:nginx怎么部署两台tomcat? upstream 在网上找的资源,我在nginx配置文件(nginx.conf)中添加了两个server.结果只显示第一个se ...
- docker镜像的常用操作
获取镜像 比如说我们可以这样操作 当然把这个镜像拉过来时间非常长. 查看镜像列表 命令: docker images 说明: 使用docker images命令可以列出本地主机上已有的镜像. 信息 ...
- Git命令行入门
安装 下载与文档地址:https://git-scm.com/book/zh/v2 我使用的是linux系统,故使用命令行安装Git # apt-get install git 配置 # git co ...
- oracle入坑日记<六>自增列创建和清除(含序列和触发器的基础用法)
0 前言 用过 SQLserver 和 MySQL 的自增列(auto_increment),然而 Oracle 在建表设置列时却没有自增列. 查阅资料后发现 Oracle 的自增列需要手动编写. ...
- thinkphp5 部署注意事项
配置tp5 需要修改设置 1. 通过yum安装的Apache,会默认安装在/etc/httpd因此配置文件也在相应的目录中 修改文件vim /etc/httpd/conf/httpd.confhttp ...