Codeforces 547C/548E - Mike and Foam 题解
Codeforces 547C/548E - Mike and Foam 题解
前置芝士 - 容斥原理
容斥原理是简单的小学奥数求多个集合的并集的算法,最基本的思想大概是如下内容:
这是一道简单例题:有\(10\)个学生喜欢唱歌,有\(15\)个学生喜欢跳舞,有\(5\)个学生两种活动都喜欢,没有不喜欢前述两种活动的学生,那么一共有多少个学生呢?
相信聪明的你已经知道答案了,答案就是由如下算式计算得来:
\]
对的,就是跟小学奥数一样。首先把喜欢唱歌或跳舞的学生都加起来,之后再减去重复计算的\(5\)个都喜欢的学生就可以了。
形式化地说(不过这里有三个集合,为了显示更多的规律):
\]
那么,如果有更多集合又该怎么算呢?其实也不难(表述可能不清楚qaq):
枚举所有集合组成的集合的子集(也就是01枚举每个集合),如果当前枚举的子集的个数是奇数,那么就加上它们交集的大小,否则(也就是偶数),就减去它们交集的大小。
形式化地说(这个应该清楚了):
\bigcup_{i=1}^{n}S_i
\vert
=
\sum_{T \subseteq U}
(-1)^{\vert T \vert - 1}
\vert
\bigcap_{E \in T}E
\vert
\]
\(S_i\)表示第\(i\)个要被求并集的集合,\(U\)表示把所有\(S_i\)作为元素的集合,\(T\)表示枚举出来的当前的\(U\)的子集,同样,\(T\)的每个元素都是一个集合,\(\vert T \vert\)表示\(T\)的包含的集合的个数,\(E\)表示如\(S_i\)一般包含普通的元素的集合。
题意
题意很简单,给你\(n\)杯啤酒,每个啤酒有数\(a_i\)和\(q\)个操作,每个查询包含一个数\(x\),表示对第\(x\)杯啤酒操作。如果这杯啤酒在架子上,就把它拿下来,否则,就放上去。之后输出当前放在架子上的啤酒里,上面的数互质的啤酒的对数,形式化地说,就是:
输出\((i,j)\)的对数,当它们满足\(i<j\)且\(\gcd(a_i,a_j)=1\),\(\gcd\)表示最大公因数。
以下把啤酒直接就叫做数字(它上面的那个标的数\(a_i\))了。
想法(口胡)
把每个数都拆成质因子序列,并把质因子当成是要求并集的集合,然后用容斥和一些数据结构就可以快速计算与当前数互质的数的个数。
做法
首先,我们把每个数都拆成它们的质因子相乘的序列,有相同的质因子就只保留其中的一个。然后,我们再维护一个数据结构(推荐std::map
,方便好用),保存的是枚举出的质因子相乘得到的某一个它的因数(第一关键字),以它作为因子(除以它余\(0\))的数\(a_i\)的个数(第二关键字)。之后用容斥的方法,就可以算出每一个数当前不与它互质的在架子上的数的个数,用总数减一下就是互质的数的个数了。添加和删去数也很方便:添加时就把所有它的因子(特指用枚举质因子相乘得到的)在map
里的值加上一,删除时就减去一就好了。
程序
感觉前面做法就是描述的程序写法啊(果然还是我的表述太不清楚了吧)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,q,cnt;//cnt表示在架子上的啤酒的个数
ll tot;//tot是当前的所有的互质的数对的数量
int a[200005];
map<int,int> mp;//保存包含某个数作为因数的数a[i]的个数
vector<int> p[200005];//把数拆成质因子序列
bool onshelf[200005];//是否在架子上
void ext(int x,vector<int> &ps){
if(x==1){//特判一就不拆了
return;
}
for(int i=2;i*i<=x;i++){
if(x%i==0){
ps.push_back(i);
while(x%i==0)x/=i;//去除重复的因子
}
}
if(x>1)ps.push_back(x);//循环完可能还会有一个因子没有分解
}
void puton(int x){//添加第x个数到架子
int res=cnt;//假设所有数都互质
for(int s=1;s<(1<<p[x].size());s++){//枚举当前使用的质因数的集合
int mt=1,bts=0;//mt为乘积,bts记录子集大小
for(int i=0;i<p[x].size();i++){
if(s&(1<<i)){
mt*=p[x][i];
bts++;
}
}//算出乘积
if(bts&1){
res-=mp[mt];
}else{
res+=mp[mt];
}//容斥,正负相反是因为前面假设都是互质的
mp[mt]++;//添加这个因子,由于枚举出的mt各不相同,所以不会重复计算
}
tot+=res;
}
void takeoff(int x){//拿走,基本同上
int res=cnt;
for(int s=1;s<(1<<p[x].size());s++){
int mt=1,bts=0;
for(int i=0;i<p[x].size();i++){
if(s&(1<<i)){
mt*=p[x][i];
bts++;
}
}
mp[mt]--;//先减去自己的那个因子,防止重复
if(bts&1){
res-=mp[mt];
}else{
res+=mp[mt];
}
}
tot-=res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
ext(a[i],p[i]);
}
while(q--){
int x;cin>>x;
if(onshelf[x]){
cnt--;
takeoff(x);
}else{
puton(x);
cnt++;
}
onshelf[x]^=1;//作用就是取反
cout<<tot<<endl;
}
return 0;
}
感谢
感谢你看完了!我真的是很不擅长数论qaq,如果有什么写得不清楚的欢迎在下面留言~
Codeforces 547C/548E - Mike and Foam 题解的更多相关文章
- Codeforces 548E Mike ans Foam (与质数相关的容斥多半会用到莫比乌斯函数)
题面 链接:CF548E Description Mike is a bartender at Rico's bar. At Rico's, they put beer glasses in a sp ...
- codeforces #305 C Mike and Foam
首先我们注意到ai<=50w 因为2*3*5*7*11*13*17=510510 所以其最多含有6个质因子 我们将每个数的贡献分离, 添加就等于加上了跟这个数相关的互素对 删除就等于减去了跟这个 ...
- hdu4135-Co-prime & Codeforces 547C Mike and Foam (容斥原理)
hdu4135 求[L,R]范围内与N互质的数的个数. 分别求[1,L]和[1,R]和n互质的个数,求差. 利用容斥原理求解. 二进制枚举每一种质数的组合,奇加偶减. #include <bit ...
- E. Mike and Foam(容斥原理)
E. Mike and Foam Mike is a bartender at Rico's bar. At Rico's, they put beer glasses in a special sh ...
- cf#305 Mike and Foam(容斥)
C. Mike and Foam time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...
- # Codeforces Round #529(Div.3)个人题解
Codeforces Round #529(Div.3)个人题解 前言: 闲来无事补了前天的cf,想着最近刷题有点点怠惰,就直接一场cf一场cf的刷算了,以后的题解也都会以每场的形式写出来 A. Re ...
- Codeforces Round #557 (Div. 1) 简要题解
Codeforces Round #557 (Div. 1) 简要题解 codeforces A. Hide and Seek 枚举起始位置\(a\),如果\(a\)未在序列中出现,则对答案有\(2\ ...
- Codeforces Round #665 (Div. 2)A-C题解
A. Distance and Axis 题目:http://codeforces.com/contest/1401/problem/A 题解:对于n来说分两种情况,一是奇数,二则是偶数 ①奇数:对于 ...
- Codeforces Round #668 (Div. 2)A-C题解
A. Permutation Forgery 题目:http://codeforces.com/contest/1405/problem/A 题解:这道题初看有点吓人,一开始居然想到要用全排序,没错我 ...
随机推荐
- 洛谷P2569 (BZOJ1855)[SCOI2010]股票交易 【单调队列优化DP】
Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价 ...
- k8s 开船记-修船:改 readinessProbe ,去 DaemonSet ,上 Autoscaler
(图片来自网络) 改 readinessProbe 对于昨天 k8s 尼克号发生的触礁事故,我们分析下来主要是2个原因,一是当时4个节点不够用造成部分容器负载过高而宕机,二是 readinessPro ...
- Shell排序 C&&C++
Shell排序 Shell排序是大量数据需要排序时,更为高效的插入排序.它的算法思想基于插入排序的算法思想 流程: (1)将n个元素数组分成n/2个数字序列,第一个数据和第n/2个数据为一对,等等 ...
- 【CentOS7】设置静态IP地址
[CentOS7]设置静态IP地址 转载:https://www.cnblogs.com/yangchongxing/p/10645871.html 图像化修改 nmtui 查看当前网卡名称 # if ...
- hibernate mysql中文检出无效
在学习ssh框架是发现,检索条件是英文时,sql就能按照条件过滤出数据,当我换成中文是,检索出来的数据就是空,最后发现没有设置数据库连接url的编码格式 1.数据库编码 COLLATE='utf8_g ...
- Windows10 中的字母映射表
有很多朋友为寻找特殊字符串而感到烦恼, windows10中的字符映射表有所有字体 包含的特殊符号 windows键 + R键 输入 charmap 点击确定 即可出现 字母映射表 可在字符的下拉按钮 ...
- django基础之day05,F与Q查询,Q查询的高级用法
#F与Q查询 #*************************** F 查询 ******************** # F 查询数据库中的其他字段!!! #1.查询库存数大于卖出数的书籍 fr ...
- before和after的操作
before和after,前者是在元素之前插入东西,后者是在元素后面插入东西,但插入的东西不仅仅只是文字而已,还有图标,以及计算器的操作. 由于两者的操作基本一样,这里以before为例 插入文字 & ...
- 优先队列与TopK
一.简介 前文介绍了<最大堆>的实现,本章节在最大堆的基础上实现一个简单的优先队列.优先队列的实现本身没什么难度,所以本文我们从优先队列的场景出发介绍topK问题. 后面会持续更新数据结构 ...
- CSS入门(背景各种属性的详解、垂直居中和过渡效果的详解、渐变效果的简单讲解、雪碧图和精灵图)
一.各种背景属性 1.background-image 属性为元素设置背景图像. 元素的背景占据了元素的全部尺寸,包括内边距和边框,但不包括外边距. 默认地,背景图像位于元素的左上角,并在水平和垂直方 ...