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. Coderfocers-616c

    You are given a rectangular field of n × m cells. Each cell is either empty or impassable (contains ...

  2. ARTS-S gitlab与jenkins实现持续集成

    jenkins配制 系统管理->管理插件->可选插件->选择安装 Gitlab Hook Plugin和Build Authorization Token Root Plugin插件 ...

  3. 新版FPC摄像头测评 OV7725 OV7670 OV9650 OV9655 OV5640 OV5642 OV2640 OV3640 MT9D112

    新版FPC摄像头测评 OV7725 OV7670 OV9650 OV9655 OV5640 OV5642 OV2640 OV3640 MT9D112 最新制样新版FPC摄像头板卡,先看看结构尺寸 再瞧 ...

  4. Java_输入整数求阶乘

    import java.util.Scanner;public class Work4{ public static void main(String[] args){ // 创建Scanner对象 ...

  5. 信道估计之LS

    在无线通信系统中,系统的性能主要受到无线信道的制约.基站和接收机之间的传播路径复杂多变,从简单的视距传输到受障碍物反射.折射.散射影响的传播.在无线传输环境中,接收信号会存在多径时延,时间选择性衰落和 ...

  6. windows10查看电脑已经保存的wifi密码

    1,打开windows的命令窗口,输入    netsh wlan show profiles,如下图,这个命令仅仅只是查看一下电脑保存的所有的wifi名字 2,需要查看密码的话,则需要输入这个命令, ...

  7. .NET Core Razor Pages中ajax get和post的使用

    ASP.NET Core Razor Pages Web项目大部分情况下使用继承与PageModel中的方法直接调用就可以(asp-page),但是有些时候需要使用ajax调用,更方便些.那么如何使用 ...

  8. impala-shell导出数据存在中文异常问题

    由于查询在impala-shell 中没有问题,在导出数据的时候才有问题,这是impala-shell的客户端是由python编写的,而Python无法自动将unicode对象写入没有设置默认编码的输 ...

  9. HTML连载57-相对定位和绝对定位

    一.定位流 1.分类 (1)相对定位: (2)绝对定位 (3)固定定位 (4)静态定位 2.什么相对定位 相对定位就是相对于自己以前在标准流中的位置来移动. 例子: <style> div ...

  10. Linux下修改MySQL数据库数据文件路径

    使用rpm安装方式安装完MySQL数据库后,数据文件的默认路径为/var/lib/mysql,然而根目录并不适合用于存储数据文件. 原路径:/var/lib/mysql 目标路径:/home/mysq ...