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-10-12 15:21:08