zoukankan      html  css  js  c++  java
  • 省选测试42

    A 小B的棋盘

    题目大意 : 棋盘里有n个棋子,再放k个棋子,对称中心有几种

    • 按x,y为第1,2关键字排序,如果中心对称的话一定是第一个和最后一个对称,第二个和从后数第二个对称,这样的

    • 不让后放的和后放的配对,那么其一个配对,如果前k个都和后面新放的配对,那么第一个与原来就有的棋子配对的点最大也是k+1,

    • 所以k2枚举第一个都是原来就有的棋子的配对,找到对称中心,然后判断没配对的点数是否小于等于k就好了

    Code

    Show Code
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    const int N = 1e5 + 5, M = 2 << 18;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Node {
        int x, y;
    }a[N], b[500];
    
    bool operator < (const Node &a, const Node &b) {
        return a.x != b.x ? a.x < b.x : a.y < b.y;
    }
    
    struct Hash {
        int n, x, y;
    }h[N];
    int head[M], hac;
    
    void Add(int x, int y) {
        int u = (long long)((x + 1e9) * (int)1e9 + y + 1e9) % M;
        h[++hac] = (Hash) {head[u], x, y}; head[u] = hac;
    }
    
    bool Find(int x, int y) {
        int u = (long long)((x + 1e9) * (int)1e9 + y + 1e9) % M;
        for (int i = head[u]; i; i = h[i].n)
            if (h[i].x == x && h[i].y == y) return 1;
        return 0;
    }
    
    int n, m, ans, cnt;
    
    int main() {
        freopen("chess.in", "r", stdin);
        freopen("chess.out", "w", stdout);
        n = read(); m = read();
        if (m >= n) return puts("-1"), 0;
        for (int i = 1; i <= n; ++i) {
            int x = read(), y = read();
            a[i] = (Node) {x, y}; Add(x, y); 
        }
        sort(a + 1, a + n + 1);
        for (int i = 1; i <= m + 1; ++i)
            for (int j = n; j >= n - m + i - 1; --j) 
                b[++cnt] = (Node) {a[i].x + a[j].x, a[i].y + a[j].y};
        sort(b + 1, b + cnt + 1);
        for (int i = 1; i <= cnt; ++i) {
            if (i > 1 && b[i].x == b[i-1].x && b[i].y == b[i-1].y) continue;
            int tot = 0;
            for (int j = 1; j <= n && tot <= m; ++j)
                if (!Find(b[i].x - a[j].x, b[i].y - a[j].y)) tot++;
            if (tot <= m) ans++;
        }
        printf("%d
    ", ans);
        return 0;
    }
    

    B 小B的夏令营

    题目大意 : 一个矩形,一侧没有方块的方块会有概率碎掉,问有多大的概率矩形不会分成两个及以上四联通块

    • p[i]表示碎了i个的概率,

    [p[i]=inom{k}{i}(frac{a}{b})^i(1-frac{a}{b})^{k-i} ]

    • dp[i][l][r] 前i层没有塌,第i层剩下l到r的概率,

    [dp[i][l][r]=p[l-1]p[m-r]sum _{[lp,rp]cap [l,r] eq varnothing }dp[i-1][lp][rp] ]

    • f[i][j] 表示前i层没有塌,第i层j+1到最后都碎了,j是完好的,前面可以不限制的方案数

    [f[i][j]=sum_{k=1}^{j}dp[i][k][j] ]

    • s[i][j] 是 f[i][j]的前缀和

    [s[i][j]=sum_{k=1}^{j}f[i][j] ]

    • 所以

    [dp[i][l][r]=p[l-1]p[m-r](s[i-1][m]-s[i-1][l-1]-s[i-1][m-r]) ]

    [f[i][r]=sum_{l=1}^{r}p[l-1]p[m-r](s[i-1][m]-s[i-1][l-1]-s[i-1][m-r]) ]

    [f[i][r]=p[m-r]((sum_{l=1}^{r}p[l-1])(s[i-1][m]-s[i-1][m-r])+sum_{l=1}^{r}p[l-1]s[i-1][l-1]) ]

    • 所以再维护p的前缀和,p[i]*s[k][i]的前缀和即可求出答案

    Code

    Show Code
    #include <cstdio>
    
    using namespace std;
    const int N = 1505, M = 1e9 + 7, MN = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, m, k, p1, p2, p[N], sp[N], f[N][N], s[N][N], ps[N][N], fac[MN], inv[MN];
    
    int Pow(int a, int k, int ans = 1) {
        for (; k; k >>= 1, a = 1ll * a * a % M)
            if (k & 1) ans = 1ll * ans * a % M;
        return ans;
    }
    
    void Init() {
        fac[0] = 1;
        for (int i = 1; i <= k; ++i)
            fac[i] = 1ll * fac[i-1] * i % M;
        inv[k] = Pow(fac[k], M - 2);
        for (int i = k; i >= 1; --i)
            inv[i-1] = 1ll * inv[i] * i % M;
    }
    
    int C(int n, int m) {
        return 1ll * fac[n] * inv[m] % M * inv[n-m] % M;
    }
    
    int main() {
        freopen("camp.in", "r", stdin);
        freopen("camp.out", "w", stdout);
        n = read(); m = read();
        p1 = 1ll * read() * Pow(read(), M - 2) % M; 
        p2 = (1 - p1 + M) % M; 
        k = read(); Init();
        for (int i = 0; i <= m && i <= k; ++i)
            p[i] = 1ll * Pow(p1, i) * Pow(p2, k-i) % M * C(k, i) % M;
        sp[0] = p[0];
        for (int i = 1; i <= m; ++i) 
            if ((sp[i] = sp[i-1] + p[i]) >= M) sp[i] -= M;
        f[0][m] = s[0][m] = 1;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j)
                f[i][j] = (1ll * (s[i-1][m] - s[i-1][m-j] + M) * sp[j-1] - ps[i-1][j-1] + M) % M * p[m-j] % M;
            for (int j = 1; j <= m; ++j) {
                if ((s[i][j] = s[i][j-1] + f[i][j]) >= M) s[i][j] -= M;
                ps[i][j] = (ps[i][j-1] + 1ll * p[j] * s[i][j]) % M;
            }
        }
        printf("%d
    ", s[n][m]);
        return 0;
    }
    

    C 小B的图

    题目大意 : 有A条边,边权为k+x,有B条边,边权为k-x,每次给一个x,求最小生成树

    • 如果x为负无穷,最小生成树里都是A的边,如果x为正无穷,最小生成树里都是B的边

    • 所以考虑生成树里的边在x为哪些值的时候会变化,

    • 先把A的都加进去,然后插B的边,lct找链中最长的,算出来会在x为多少的时候就开始替换这条A边

    • 然后把这些A排序,查询的时候二分就行

    Code

    Show Code
    #include <cstdio>
    #include <algorithm>
    #define ls t[x].ch[0]
    #define rs t[x].ch[1]
    #define Get(x) (t[t[x].f].ch[1] == x)
    #define Nroot(x) (t[t[x].f].ch[Get(x)] == x)
    
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, A, B, m, trc, tp, stk[N*2], tm[N], tmc, f[N];
    ll s[N];
    
    struct Side {
        int x, y, d;
    }a[N*2], b[N*2];
    
    bool operator < (const Side &a, const Side &b) {
        return a.d < b.d;
    }
    
    struct Tree {
        int w, m, p, f, ch[2]; bool tag;
    }t[N*2];
    
    void Pushup(int x) {
        t[x].m = t[x].w; t[x].p = x;
        if (ls && t[ls].m > t[x].m) t[x].m = t[ls].m, t[x].p = t[ls].p;
        if (rs && t[rs].m > t[x].m) t[x].m = t[rs].m, t[x].p = t[rs].p;
    }
    
    void Pushdown(int x) {
        if (!t[x].tag) return;
        swap(ls, rs); t[x].tag = 0;
        t[ls].tag ^= 1, t[rs].tag ^= 1;
    }
    
    void Rotate(int x) {
        int y = t[x].f, z = t[y].f, k = Get(x), B = t[x].ch[k^1];
        if (Nroot(y)) t[z].ch[Get(y)] = x; t[x].f = z;
        t[x].ch[k^1] = y; t[y].f = x;
        t[y].ch[k] = B; t[B].f = y;
        Pushup(y); Pushup(x);
    }
    
    void Splay(int x) {
        for (int y = x; Nroot(y); y = t[y].f) stk[++tp] = t[y].f;
        while (tp) Pushdown(stk[tp--]); Pushdown(x);
        while (Nroot(x)) {
            int y = t[x].f;
            if (Nroot(y)) Get(x) != Get(y) ? Rotate(x) : Rotate(y);
            Rotate(x);
        }
    }
    
    void Access(int x) {
        for (int y = 0; x; y = x, x = t[x].f)
            Splay(x), rs = y, Pushup(x);
    }
    
    void Mroot(int x) {
        Access(x); Splay(x); t[x].tag ^= 1;
    }
    
    void Link(int x, int y) {
        Mroot(x); t[x].f = y;
    }
    
    void Split(int x, int y) {
        Mroot(x); Access(y); Splay(y);
    }
    
    void Cut(int x, int y) {
        Split(x, y); t[x].f = t[y].ch[0] = 0; Pushup(y);
    }
    
    int Find(int x) {
        return x == f[x] ? x : f[x] = Find(f[x]);
    }
    
    int main() {
        freopen("graph.in", "r", stdin);
        freopen("graph.out", "w", stdout);
        trc = n = read(); A = read(); B = read(); m = read();
        for (int i = 1; i <= n; ++i) t[i].w = -2e9;
        for (int i = 1; i <= A; ++i)
            a[i] = (Side) {read(), read(), read()};
        sort(a + 1, a + A + 1);
        for (int i = 1; i <= n; ++i) f[i] = i;
        for (int i = 1, cnt; i <= A && cnt < n-1; ++i) {
            int x = a[i].x, y = a[i].y, d = a[i].d, fx, fy;
            if ((fx = Find(x)) == (fy = Find(y))) continue;
            f[fx] = fy; s[0] += d;
            b[++trc] = a[i]; t[trc].w = d;
            Link(trc, x); Link(trc, y); cnt++;
        }
        for (int i = 1; i <= B; ++i)
            a[i] = (Side) {read(), read(), read()};
        sort(a + 1, a + B + 1);
        for (int i = 1; i <= n; ++i) f[i] = i;
        for (int i = 1; i <= B; ++i) {
            int x = a[i].x, y = a[i].y, d = a[i].d, fx, fy;
            if ((fx = Find(x)) == (fy = Find(y))) continue;
            f[fx] = fy; Split(x, y); 
            int p = t[y].p; Cut(p, b[p].x); Cut(p, b[p].y);
            t[p].w = -2e9; Link(p, x); Link(p, y); 
            tm[++tmc] = d - b[p].d;
        }
        sort(tm + 1, tm + tmc + 1); tm[0] = -2e9;
        for (int i = 1; i <= tmc; ++i) 
            s[i] = s[i-1] + tm[i];
        while (m--) {
            int x = read(), l = 0, r = n - 1;
            while (l < r) {
                int mid = l + r + 1 >> 1;
                if (x * 2 >= tm[mid]) l = mid;
                else r = mid - 1;
            }
            printf("%lld
    ", s[l] + 1ll * (n - 1 - l - l) * x);
        }
        return 0;
    }
    
  • 相关阅读:
    There is an overlap in the region chain修复
    There is an overlap in the region chain
    region xx not deployed on any region server
    python 中的re模块,正则表达式
    TCP粘包问题解析与解决
    yield from
    Git push提交时报错Permission denied(publickey)...Please make sure you have the correct access rights and the repository exists.
    mysql 中Varchar 与char的区别
    Mysql 字符集及排序规则
    请实现一个装饰器,限制该函数被调用的频率,如10秒一次
  • 原文地址:https://www.cnblogs.com/shawk/p/14564556.html
Copyright © 2011-2022 走看看