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 要你求覆盖奇数次的矩形面积并,每次更新时减去原先的值即可实现奇数次有效,下推时为保证线段长度不变左 ...
随机推荐
- 如何破解QQ空间相册密码访问权限2019方法
今天小编给大家介绍一下最新的QQ空间相册破解方法,是2019年最新方法,本方法来自互联网,下面开始方法教程 教程之前我们需要下载软件,地址我发在下方 软件切图 1.首先我们打开软件,然后在“操作界面” ...
- VS2017 ASP.NET MVC 5.0 开部署问题汇总
1[SqlException (0x80131904): 拒绝了对对象 '****' (数据库 '***',架构 'dbo')的 EXECUTE 权限.] “/”应用程序中的服务器错误. SQL 20 ...
- Python全栈开发记录_第四篇(集合、函数等知识点)
知识点1:深拷贝和浅拷贝 非拷贝(=赋值:数据完全共享,内存地址一样,修改一个另一个也变化) 浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)像[[1,2],3,4]如果修改列表中列 ...
- linux下导入、导出mysql数据库命令的实现方法
首先建空数据库 mysql>create database abc; 导入数据库 mysql>use abc; 设置数据库编码 mysql>set names utf8; 导入数据( ...
- springboot学习随笔(四):Springboot整合mybatis(含generator自动生成代码)
这章我们将通过springboot整合mybatis来操作数据库 以下内容分为两部分,一部分主要介绍generator自动生成代码,生成model.dao层接口.dao接口对应的sql配置文件 第一部 ...
- WEB日志分析工具(Webslizer和AWstats)
https://www.cnblogs.com/xiaowenshu/p/10030139.html#top
- Java JTable列顺序和列宽度保存在用户本地
上周碰到了一个棘手的需求,就是要把用JTable的列顺序和列宽度保存下来,这次用户调整了列宽度,关闭程序,下次再打开时,这个列的宽还是要保持,因为SWing的特性,都是在程序启动时就确定了列顺序和列宽 ...
- C#对象与XMl文件之间的相互转换(转)
本文是对C#中对象与XMl文件之间的相互转换进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助 C#提供三种序列化方式,分别为:1.是使用BinaryFormatter进行串行化: 2.使 ...
- Windows下查看自己电脑的网关mac以及手动获取新的地址
场景:正在上班时,工作电脑突然无法连接网络了.查看配置发现DNS服务器地址被分配到了192.168.1.1,瞬间懵了? 过程:(1)进入cmd.使用ipconfig /all查看网关地址; (2)使用 ...
- java将错误信息写入文件
第一种办法可以通过字符串,也就是先把错误信息写入字符串,再将字符串写入文件 import java.io.*; public class Demo { public static void main( ...