Codeforces 547C/548E - Mike and Foam 题解

前置芝士 - 容斥原理

容斥原理是简单的小学奥数求多个集合的并集的算法,最基本的思想大概是如下内容:

这是一道简单例题:有\(10\)个学生喜欢唱歌,有\(15\)个学生喜欢跳舞,有\(5\)个学生两种活动都喜欢,没有不喜欢前述两种活动的学生,那么一共有多少个学生呢?

相信聪明的你已经知道答案了,答案就是由如下算式计算得来:

\[10+15-5=20(个)
\]

对的,就是跟小学奥数一样。首先把喜欢唱歌或跳舞的学生都加起来,之后再减去重复计算的\(5\)个都喜欢的学生就可以了。

形式化地说(不过这里有三个集合,为了显示更多的规律):

\[\vert A \cup B \cup C \vert = \vert A \vert + \vert B \vert + \vert C \vert - \vert A \cap B \vert - \vert A \cap C \vert - \vert B \cap C \vert + \vert A \cap B \cap C \vert
\]

那么,如果有更多集合又该怎么算呢?其实也不难(表述可能不清楚qaq):

枚举所有集合组成的集合的子集(也就是01枚举每个集合),如果当前枚举的子集的个数是奇数,那么就加上它们交集的大小,否则(也就是偶数),就减去它们交集的大小。

形式化地说(这个应该清楚了):

\[\vert
\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 题解的更多相关文章

  1. 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 ...

  2. codeforces #305 C Mike and Foam

    首先我们注意到ai<=50w 因为2*3*5*7*11*13*17=510510 所以其最多含有6个质因子 我们将每个数的贡献分离, 添加就等于加上了跟这个数相关的互素对 删除就等于减去了跟这个 ...

  3. hdu4135-Co-prime & Codeforces 547C Mike and Foam (容斥原理)

    hdu4135 求[L,R]范围内与N互质的数的个数. 分别求[1,L]和[1,R]和n互质的个数,求差. 利用容斥原理求解. 二进制枚举每一种质数的组合,奇加偶减. #include <bit ...

  4. 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 ...

  5. cf#305 Mike and Foam(容斥)

    C. Mike and Foam time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  6. # Codeforces Round #529(Div.3)个人题解

    Codeforces Round #529(Div.3)个人题解 前言: 闲来无事补了前天的cf,想着最近刷题有点点怠惰,就直接一场cf一场cf的刷算了,以后的题解也都会以每场的形式写出来 A. Re ...

  7. Codeforces Round #557 (Div. 1) 简要题解

    Codeforces Round #557 (Div. 1) 简要题解 codeforces A. Hide and Seek 枚举起始位置\(a\),如果\(a\)未在序列中出现,则对答案有\(2\ ...

  8. Codeforces Round #665 (Div. 2)A-C题解

    A. Distance and Axis 题目:http://codeforces.com/contest/1401/problem/A 题解:对于n来说分两种情况,一是奇数,二则是偶数 ①奇数:对于 ...

  9. Codeforces Round #668 (Div. 2)A-C题解

    A. Permutation Forgery 题目:http://codeforces.com/contest/1405/problem/A 题解:这道题初看有点吓人,一开始居然想到要用全排序,没错我 ...

随机推荐

  1. CoderForces-Round60D(1117) Magic Gems

    D. Magic Gems time limit per test 3 seconds memory limit per test 256 megabytes input standard input ...

  2. A.Two Rival Students

    题目:两个竞争的学生 链接:(两个竞争的对手)[https://codeforces.com/contest/1257/problem/A] 题意:有n个学生排成一行.其中有两个竞争的学生.第一个学生 ...

  3. 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享

    写在前面的话&&About me 网上写spring的文章多如牛毛,为什么还要写呢,因为,很简单,那是人家写的:网上都鼓励你不要造轮子,为什么你还要造呢,因为,那不是你造的. 我不是要 ...

  4. [Input-number]数字输入框组件

    需求 加.减按钮 初始值 最大.最小值 数值改变时,触发一个自定义事件来通知父组件 目录文件 index.html 入口页 input-number.js 数字输入框组件 index.js 根实例 实 ...

  5. Python3 函数实践之简易购物系统

    函数实践之简易购物系统 项目主要需求: 用户可以自行选择功能 该购物系统具有注册/登录/购物/购物车/退出登录功能 用户在登录后才能使用购物/购物车/退出登录功能 ''' 注册 登录 购物 购物车 退 ...

  6. 【CuteJavaScript】ES2019 新特性汇总

    最近 ECMAScript2019,最新提案完成:tc39 Finished Proposals,我这里也是按照官方介绍的顺序进行整理,如有疑问,可以查看官方介绍啦~ 另外之前也整理了 <ES6 ...

  7. 【Redis】270- 你需要知道的那些 redis 数据结构

    本文出自「掘金社区」,欢迎戳「阅读原文」链接和作者进行技术交流 ?? 作者简介 世宇,一个喜欢吉他.MDD 摄影.自走棋的工程师,属于饿了么上海物流研发部.目前负责的是网格商圈.代理商基础产线,平时喜 ...

  8. 阿里巴巴的26款Java开源项目

    阿里巴巴的26款Java开源项目 开源展示了人类共同协作,成果分享的魅力.没有任何一家网络公司可以不使用开源技术,仅靠自身技术发展起来.“取之于开源,用之于开源,才能促进开源的良性发展”,阿里巴巴各个 ...

  9. where和having区别

    壹: where后面不能跟聚合函数(sum.avg.count.max.min) having后面可以跟 贰: where和having都能用: select goods_price,goods_na ...

  10. android studio 代码问题总结

    1,android studio隐藏title时,用eclipse里面的方法不行,所以用下面的代码解决,此代码需要写在 加载xml文件之后 getSupportActionBar().hide(); ...