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;
    }
    
  • 相关阅读:
    c# 代码控制文件夹权限时,只显示特殊权限的问题
    C#使用SQLite数据库遇到的问题(二)
    GC工作原理
    Thread
    -static
    String 练习题
    更进ATM
    继承 示例
    数组
    求奇偶数
  • 原文地址:https://www.cnblogs.com/shawk/p/14564556.html
Copyright © 2011-2022 走看看