E. Mike and Foam 容斥原理

http://codeforces.com/problemset/problem/548/E

这题是询问id,如果这个id不在,就插入这个id,然后求a[id1] ,  a[id2]互质的对数。

询问有多少个互质这个套路出了很多次,这次是在线

首先维护当前的ans,可以知道每一步的ans,都是由于上一步的ans递推过来的。就是小答案可以由大答案推过来。

就是现在数组是a[] = 1, 2, 3,维护一个ans表示有多少对gcd等于1,然后添加一个4,只需要询问4在a[] = {1, 2, 3}中有多少个和它互质,即可。

(有时候也需要总体分析。-  - ,与这题无关)

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 510510 + 20;
int prime[maxn][22], a[maxn];
void init() {
    for (int i = 2; i <= maxn - 20; ++i) {
        if (prime[i][0]) continue;
        for (int j = i; j <= maxn - 20; j += i) {
            prime[j][++prime[j][0]] = i;
        }
    }
//    prime[1][0] = 1;
//    prime[1][1] = 1;
}
bool in[maxn];
int num[maxn];
void maintain(int val, int op) {
    int en = (1 << prime[val][0]) - 1;
    for (int i = 1; i <= en; ++i) {
        int res = 1;
        for (int j = 1; j <= prime[val][0]; ++j) {
            if (i & (1 << (j - 1))) res *= prime[val][j];
        }
        num[res] += op;
    }
}
LL ans;
LL getAns(int val) {
    LL ans = 0;
    int en = (1 << prime[val][0]) - 1;
    for (int i = 1; i <= en; ++i) {
        int res = 1;
        int sel = 0;
        for (int j = 1; j <= prime[val][0]; ++j) {
            if (i & (1 << (j - 1))) {
                ++sel;
                res *= prime[val][j];
            }
        }
        if (sel & 1) ans += num[res];
        else ans -= num[res];
    }
    return ans;
}
void work() {
    int n, q, tot = 0;
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    for (int i = 1; i <= q; ++i) {
        int id;
        scanf("%d", &id);
        if (in[id]) {
            maintain(a[id], -1);
            in[id] = false;
            ans -= getAns(a[id]);
            tot--;
        } else {
            ans += getAns(a[id]);
            maintain(a[id], 1);
            in[id] = true;
            tot++;
        }
        printf("%I64d\n", 1LL * tot * (tot - 1) / 2 - ans);
    }
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    init();
//    int val = 4;
//    for (int i = 1; i <= prime[val][0]; ++i) {
//        printf("%d ", prime[val][i]);
//    }
//    printf("\n");
    work();
    return 0;
}

http://www.cnblogs.com/liuweimingcprogram/p/6919379.html

时间: 2024-08-04 19:41:27

E. Mike and Foam 容斥原理的相关文章

Codeforces Round #305 (Div. 2) E. Mike and Foam 容斥原理

在一个集合中,找和x互素的数有多少? 用容斥定理,先把每个数质因数分解(每个数至多有6个质因子),奇减偶加,就统计到和x互素的数了. 代码: #include<iostream> #include<vector> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int N = 5*100000+10; const int maxn

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 shelf. There are n kinds of beer at Rico's numbered from 1 to n. i-th kind of beer has ai milliliters of foam on it. Maxim is Mike's boss. Today he told

Codeforces548E:Mike and Foam

Mike is a bartender at Rico's bar. At Rico's, they put beer glasses in a special shelf. There are n kinds of beer at Rico's numbered from 1to n. i-th kind of beer has ai milliliters of foam on it. Maxim is Mike's boss. Today he told Mike to perform q

Codeforces Round #305 (Div. 1)C. Mike and Foam(素数+容斥)

题目链接:点这里!!! 题意: 输入n(n<=2e5),q(q<=2e5).紧接着输入n个数a1~an(ai<=5e5).给定一个空集合. 针对每个q,输入x,如果a[x]在不在集合里面,将a[x]插入进去,并且求当前该集合中有多少对互质的数: 如果a[x]在集合里面,将a[x]删除,并且求当前该集合有多少对互质的数. 题解: 1. 将所有数的素因子求出来.(最多6个) 2.如果将a[x]插入进去,我们检查由a[x]的素因子能组成的数有哪些,全部+1. 比如a[x]=12,我们将2.3.

Codeforces 547C Mike and Foam 容斥

题目链接:点击打开链接 题意: 给定n个数,q个操作 下面n个数 a1-an 开始有一个空的集合 每个操作一个数字 u (1<=u<=n) 表示把 a[u] 插入集合(若集合中没有a[u]), 否则就把a[u]从集合中删除 每个操作结束后输出 当前集合内有多少对数 是互质的. 思路: 分解质因素,然后容斥一下求 与a[u] 不互质的个数,做个差即可. PS: 在微软(苏州)bop现场和kuangbin,19891101 ,Jayye, xiaoxin等晚上一起在宾馆打的cf~ #include

Codeforces Round #305 (Div. 1)

547A - Mike and Frog Solution:  先求出两种变化的第一次和第二次变化到目标的时间. 对这四个时间的具体情况需要一些特判 . 然后直接从1到2*N枚举其中一个时间的倍数,然后输出第一个满足要求的答案.  或者求出循环节后用拓展欧几里得求出最小解. 547B - Mike and Feet 题意: 给定一个长度为n(<=2*10^5)的序列,分别求出长度为(1~n)的区间的最小数的最大值. Solution: 可以先预处理以每个数为答案的最长区间. 即从每个数分别从左和

Codeforces Round #305 (Div. 1) A.B.C 解题报告

A. Mike and Frog 枚举. 先是找循环,然后很容易得出一个两元一次方程,然后可以发现解也是有循环节的,所以最小的那个肯定出现在一定范围内,否则就后面也不可能出现.假设两个变量为x,y,系数分别为z1,z2.很显然,两者的最小公倍数便是一个周期,所以如果枚举x的话,只需要枚举到z2就可以了. 细节比较多..错了好多次..比赛中也跪了.. 代码如下: #include <iostream> #include <string.h> #include <math.h&g

UVA 11014 - Make a Crystal(容斥原理)

UVA 11014 - Make a Crystal 题目链接 题意:给定一个NxNxN的正方体,求出最多能选几个整数点.使得随意两点PQ不会使PQO共线. 思路:利用容斥原理,设f(k)为点(x, y, z)三点都为k的倍数的点的个数(要扣掉一个原点O).那么全部点就是f(1),之后要去除掉共线的,就是扣掉f(2), f(3), f(5)..f(n).n为素数.由于这些素数中包括了合数的情况,而且这些点必定与f(1)除去这些点以外的点共线,所以扣掉.可是扣掉后会扣掉一些反复的.比方f(6)在f

BZOJ3198 SDOI2013 spring HASH+容斥原理

题意:给定6个长度为n的数列,求有多少个数对(i,j)((i,j)≡(j,i))使得i和j位置恰好有K个数相同,其中0≤K≤6 题解: 设fi=至少有K个数相同的位置对的数量,用2^6枚举每一种可能,根据容斥原理,答案就是\[\sum\limits_{i = K}^N {{f_i}C_i^K{{\left( { - 1} \right)}^{i - K}}} \] 至于多乘一个组合数,是因为当前枚举到有x个数相同,一个位置对有i个相同的数,那么累计的时候就会算成$C_x^i$,因此实际上这个位置