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 要你求覆盖奇数次的矩形面积并,每次更新时减去原先的值即可实现奇数次有效,下推时为保证线段长度不变左 ...
随机推荐
- Java核心-多线程-并发控制器-Semaphore信号量
Semaphore是非常有用的一个多线程并发控制组件(Java还有CountDownLatch.CyclicBarrier.Exchanger多线程组件),它相当于是一个并发控制器,是用于管理信号量的 ...
- 软件推荐----截图软件Snagit
截图软件,比较推荐使用Snagit,功能上所有截图软件有的他都有.Snagit编辑器有一个[库]功能,可以按日期以及应用程序对截图进行分类整理,最赞的是你可以把整个库备份导出,在新的电脑上进行导入,所 ...
- related_name
定义表Apple: class Apple( models.Model): origin_level = models.ForeignKey(AppleLevel) new_level = model ...
- Oracle 生成Guid;Oracle 生成多个Guid;Oracle 生成带''-"的Guid
Oracle 生成Guid select sys_guid() from dual Oracle 生成多个Guid Oracle 生成带''-"的Guid , ) , ) || '-' || ...
- Mac安装Python3后,如何将默认执行的Python2改为Pyhton3
Mac 笔记本电脑系统自带的Python版本一般是Python 2.7,如果安装了Python 3.x,在终端中输入python命令后,输出的信息还是Python 2.7,问题就是如何将Mac系统默认 ...
- Django建站+Vuejs前端
第一节 @注意 千万注意格式.标签名字: 浏览器开发者模式修改页面不显示:在开发者模式下(F12进入),打开设置页面(F1),勾选 Disable cache (while DevTools is o ...
- MVC人员管理系统
基本都要使用C控制器中的两个action来完成操作,一个用于从主界面跳转到新页面.同时将所需操作的数据传到新界面,另一个则对应新界面的按钮,用于完成操作.将数据传回主界面以及跳转回主界面.根据不同情况 ...
- 1. maven 手动添加jar包
mvn install:install-file -Dfile=isc_sso_agent-1.0.jar -DgroupId=com.sgcc.isc -DartifactId=isc_sso_ag ...
- HTTP发送RAW请求注意的问题
1.使用jar httpcomponents-client-4.5.6-bin.tar.gz 解压后倒入lib中的所有包 2.参考代码如下 import org.apache.http.HttpRes ...
- C++使用指针的优点
使用指针可以带来如下的好处: (1)可以提高程序的编译效率和执行速度,使程序更加简洁. (2)通过指针被调用函数可以向调用函数处返回除正常的返回值之外的其他数据,从而实现两者间的双向通信. (3)利用 ...