20200215题解

OJ 1098

贪心,在遇到检查点的时候保留最大的v个元素即可,用优先队列进行优化。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

inline long long read(){
    long long ans = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
        f *= (ch == '-') ? -1 : 1, ch = getchar();
    do ans = ((ans << 1) + (ans << 3) + (ch ^ 48)), ch = getchar();
    while(ch >= '0' && ch <= '9');
    return ans * f;
}

const int MAXN = 200001;
int a[MAXN], op[MAXN];
priority_queue<int, vector<int>, greater<int> > q;

int main(){
    int n = read();
    for(int i=1; i<=n; i++)
        op[i] = (getchar() == 'e'), a[i] = read();
    for(int i=1; i<=n-1; i++){
        if(!op[i]) q.push(a[i]);
        else while(q.size() >= a[i])
            q.pop();
    }
    if(q.size() < a[n]){
        printf("-1");
        return 0;
    }
    int ans = 0;
    while(!q.empty())
        ans += q.top(), q.pop();
    printf("%d", ans);
    return 0;
}
View Code

OJ 1099

对任意的两条横着的边计算竖着的边的交点,最后取组合,这是$O(n^3)$算法,将一维转为线段树(树状数组)可以达到$O(n^2logn)$

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

inline long long read(){
    long long ans = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
        f *= (ch == '-') ? -1 : 1, ch = getchar();
    do ans = ((ans << 1) + (ans << 3) + (ch ^ 48)), ch = getchar();
    while(ch >= '0' && ch <= '9');
    return ans * f;
}

const int MAXN = 200001, SIZE = MAXN * 6;
struct line{
    int posY, posX, end;
    const bool operator < (const line &x)const{
        if(posY != x.posY) return posY < x.posY;
        return posX < x.posX;
    }
}column[MAXN], row[MAXN];
int cntC = 0, cntR = 0;
int hash[MAXN*6];

struct point{
    int y, x, val;
    const bool operator < (const point &a)const{
        if(y != a.y) return y > a.y;
        return x > a.x;
    }
};
priority_queue<point> q; 

int seg[SIZE + 1];

inline void add(int x,int val){
    for(int i=x; i<=SIZE; i+=i&(-i))
        seg[i] += val;
}

inline int ask(int x){
    int ans = 0;
    for(int i=x; i; i-=i&(-i))
        ans += seg[i];
    return ans;
}

inline int query(int l,int r){
    return ask(r) - ask(l-1);
}

inline int ord(int val){
    return lower_bound(hash + 1, hash + 1 + hash[0], val) - hash;
}

int main(){
    int n = read();
    for(int i=1; i<=n; i++){
        int y1 = read(), x1 = read(), y2 = read(), x2 = read();
        if(x1 > x2) swap(x1, x2);
        if(y1 > y2) swap(y1, y2);
        hash[++hash[0]] = x1, hash[++hash[0]] = x2;
        hash[++hash[0]] = y1, hash[++hash[0]] = y2;
        if(x1 == x2) column[++cntC] = (line){y1, x1, y2};
        else if(y1 == y2) row[++cntR] = (line){y1, x1, x2};
    }
    sort(hash + 1, hash + 1 + hash[0]);
    hash[0] = unique(hash + 1, hash + 1 + hash[0]) - hash - 1;
    for(int i=1; i<=cntC; i++)
        column[i].posX = ord(column[i].posX), column[i].posY = ord(column[i].posY), column[i].end = ord(column[i].end);
    for(int i=1; i<=cntR; i++)
        row[i].posX = ord(row[i].posX), row[i].posY = ord(row[i].posY), row[i].end = ord(row[i].end);
    sort(column + 1, column + 1 + cntC);
    sort(row + 1, row + 1 + cntR);
    long long ans = 0;
    for(int i=1; i<=cntR; i++){
        for(int j=1; j<=cntC; j++)
            if(column[j].posX >= row[i].posX && column[j].posX <= row[i].end && column[j].posY <= row[i].posY && column[j].end >= row[i].posY)
                q.push((point){column[j].posY, column[j].posX, 1}), q.push((point){column[j].end + 1, column[j].posX, -1});
        for(int j=i+1; j<=cntR; j++){
            while(!q.empty() && q.top().y <= row[j].posY)
                add(q.top().x, q.top().val), q.pop();
            int cnt = query(row[j].posX, row[j].end);
            ans += cnt * (cnt - 1) / 2; 
        }
        while(!q.empty())
            add(q.top().x, q.top().val), q.pop();
    }
    printf("%lld", ans);
    return 0;
}
View Code

OJ 1100

容斥定理(莫比乌斯反演),将$gcd==d$转化为$d|gcd$之后根据a数组的情况进行组合即可

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

inline long long read(){
    long long ans = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
        f *= (ch == '-') ? -1 : 1, ch = getchar();
    do ans = ((ans << 1) + (ans << 3) + (ch ^ 48)), ch = getchar();
    while(ch >= '0' && ch <= '9');
    return ans * f;
}

const int MAXN = 300001, MOD = 1000000007;
int mu[MAXN], prime[MAXN >> 3];
bool isPrime[MAXN];
int num[MAXN], cnt[MAXN], F[MAXN];
int fac[MAXN], inv[MAXN];

void euler(int n){
    memset(isPrime, true, sizeof(isPrime));
    mu[1] = 1;
    for(int i=2; i<=n; i++){
        if(isPrime[i]){
            prime[++prime[0]] = i;
            mu[i] = -1;
        }
        for(int j=1; j<=prime[0]; j++){
            if(i * prime[j] > n)
                break;
            isPrime[i * prime[j]] = false;
            if(i % prime[j] == 0){
                mu[i * prime[j]] = 0;
                break;
            }
            mu[i * prime[j]] = -mu[i];
        }
    }
}

inline int pow(int a,int p){
    int ans = 1;
    while(p){
        if(p & 1) ans = (long long)ans * a % MOD;
        a = (long long)a * a % MOD, p >>= 1;
    }
    return ans;
}

inline int C(int n,int m){
    return (long long)fac[n] * inv[m] % MOD * inv[n-m] % MOD;
}

int main(){
    int n = read(), m = read(), k = read();
    euler(m);
    for(int i=1; i<=n; i++)
        num[read()]++;
    fac[0] = 1;
    for(int i=1; i<=n; i++)
        fac[i] = (long long)fac[i-1] * i % MOD;
    inv[n] = pow(fac[n], MOD-2);
    for(int i=n-1; i>=0; i--)
        inv[i] = (long long)inv[i+1] * (i+1) % MOD;
    for(int i=1; i<=m; i++)
        for(int j=i; j<=m; j+=i)
            cnt[i] += num[j];
    for(int i=1; i<=m; i++)
        F[i] = (cnt[i] < n-k) ? 0 : (long long)C(cnt[i], n-k) * pow(m/i-1, cnt[i]-(n-k)) % MOD * pow(m/i, n-cnt[i]) % MOD;
    for(int i=1; i<=m; i++){
        int ans = 0;
        for(int j=i; j<=m; j+=i)
            if(mu[j/i])
                ans = ((long long)mu[j/i] * F[j] % MOD + ans + MOD) % MOD;
        printf("%d", ans);
        if(i != m) putchar(' ');
    }
    return 0;
}
View Code

OJ 1414

两个可持久化树,一个可持久化并查集,一个可持久化线段树,相当于要写两遍代码,但由于第一个可持久化并查集只有最后才有查询,所以可以离线操作,省时间复杂度又省空间复杂度,第二个只能强行线段树了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <utility>
using namespace std;

inline long long read(){
    long long ans = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
        f *= (ch == '-') ? -1 : 1, ch = getchar();
    do ans = ((ans << 1) + (ans << 3) + (ch ^ 48)), ch = getchar();
    while(ch >= '0' && ch <= '9');
    return ans * f;
}

int n, m, size;
const int MAXN = 200001;
struct Segment{
    struct Node{
        int sum, son[2];
    }node[MAXN << 5];
    int head[MAXN], nodeNum;
    void build(int &x,int l = 1,int r = size){
        x = ++nodeNum;
        if(l == r) return;
        int mid = (l + r) >> 1;
        build(node[x].son[0], l, mid);
        build(node[x].son[1], mid+1, r);
    }
    void update(int &x,int pos,int l = 1,int r = size){
        node[++nodeNum] = node[x];
        x = nodeNum;
        node[x].sum++;
        if(l == r) return;
        int mid = (l + r) >> 1;
        if(pos <= mid) update(node[x].son[0], pos, l, mid);
        else update(node[x].son[1], pos, mid+1, r);
    }
    int query(int u,int v,int k,int l = 1,int r = size){
        if(l == r) return l;
        int x = node[node[v].son[0]].sum - node[node[u].son[0]].sum, mid = (l + r) >> 1;
        if(x >= k) return query(node[u].son[0], node[v].son[0], k, l, mid);
        else return query(node[u].son[1], node[v].son[1], k-x, mid+1, r);
    }
}T;

int op[MAXN], a[MAXN], b[MAXN];
int val[MAXN], fa[MAXN];

inline int get(int x){
    if(fa[x] == x) return x;
    return fa[x] = get(fa[x]);
}

int main(){
    n = read(), m = read();
    for(int i=1; i<=n; i++)
        val[i] = read(), fa[i] = i;
    for(int i=1; i<=m; i++){
        op[i] = read();
        if(op[i] == 1) a[i] = read(), b[i] = read();
        else a[i] = read();
    }
    int p = m;
    while(p){
        if(op[p] == 1){
            fa[get(a[p])] = get(b[p]);
            p--;
        }
        else p = a[p];
    }
    int u = read(), q = read();
    for(int i=1; i<=n; i++)
        if(get(u) == get(i))
            a[++a[0]] = val[i];
    for(int i=1; i<=a[0]; i++)
        b[i] = a[i];
    sort(b+1, b+1+a[0]);
    size = unique(b+1, b+1+a[0]) - b - 1;
    for(int i=1; i<=a[0]; i++)
        a[i] = lower_bound(b+1, b+1+size, a[i]) - b;
    T.build(T.head[0]);
    for(int i=1; i<=n; i++){
        T.head[i] = T.head[i-1];
        T.update(T.head[i], a[i]);
    }
    for(int i=1; i<=q; i++){
        int l = read(), r = read(), k = read();
        printf("%d
", b[T.query(T.head[l-1], T.head[r], k)]);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/PHDHD/p/12312424.html