• 【训练】9.13 训练赛


    A. HDU 6230

    一个合法的子串(s = 3n - 2)满足条件即1-2n-1 为以n为回文中心的回文串,n-3n-2为以2n-1为中心的回文串。故我们可以通过寻找回文中心对,来判断相应合法子串的个数。利用manacher求出每个位置的最长回文半径,则若i,j满足条件(i < j) ,则应有 (p[i] geqslant  j - i + 1), (p[j] geqslant  j - i + 1)。变换一下有 (j leqslant p[i] + i + 1),(j - p[j] + 1 geqslant i < j)。所以扫描第一维,然后树状数组区间查询第二维即可。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 1000000
    #define int long long
    #define lowbit(i) (i & (-i))
    int n, ans, C[maxn], pld[maxn];
    char s[maxn];
    
    int read() {
        int x = 0, k = 1; 
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    struct node {
        int num, id;
        friend bool operator <(node x, node y) {
            return x.num > y.num;
        }
    }b[maxn];
    
    void Add(int x, int y) {
        for(int i = x; i <= n; i += lowbit(i)) C[i] += y;
    }
    
    int Que(int x) {
        int ans = 0;
        for(int i = x; i; i -= lowbit(i)) ans += C[i];
        return ans;
    }
    
    void Manacher() {
        int mx = 0, id = 0;
        for(int i = 1; i <= n; i ++) {
            pld[i] = 0;
            if(mx >= i) {
                int j = 2 * id - i; 
                pld[i] = min(pld[j], mx - i + 1);
            }
            else pld[i] = 1;
            int r = min(n - i, i - 1);
            while(pld[i] <= r && s[i + pld[i]] == s[i - pld[i]]) pld[i] ++;
            if(i + pld[i] - 1 > mx) mx = i + pld[i] - 1, id = i;
        }
    }
    
    signed main() {
        int T = read();
        while(T --) {
            scanf("%s", s + 1); n = strlen(s + 1), ans = 0;
            Manacher();
            for(int i = 1; i <= n; i ++) C[i] = 0;
            for(int i = 1; i <= n; i ++) b[i].num = pld[i] + i - 1, b[i].id = i;
            sort(b + 1, b + 1 + n);
            for(int i = n, j = 1; i >= 1; i --) {
                while(j <= n && b[j].num >= i) Add(b[j].id, 1), j ++;
                ans += Que(i - 1) - Que(i - pld[i]); 
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }

    B.HDU 6231

    二分答案。设二分的答案为mid,则考虑统计第k大数大于等于mid的区间共有多少个。把所有大于等于mid的数看做有效数字,等价于统计其中含有至少k个有效数字的区间的个数。若此时区间个数少于s,说明答案应当减小。若大于等于,则增大答案继续寻找。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 200000
    #define int long long
    #define INF 2000000000LL
    int n, k, m, a[maxn], b[maxn], sum[maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    bool Check(int mid) {
        int ans = 0;
        for(int i = 1; i <= n; i ++) 
            if(a[i] >= mid) b[i] = 1;
            else b[i] = 0;
        for(int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + b[i];
        for(int i = 1, j = 0; i <= n; i ++) {
            while(j < n && sum[i] - sum[j] >= k) j ++;
            ans += j;
        }
        return ans < m;
    }
    
    signed main() {
        int T = read();
        while(T --) {
            n = read(), k = read(), m = read();
            int l = INF, r = -INF;
            for(int i = 1; i <= n; i ++) 
                a[i] = read(), l = min(l, a[i]), r = max(r, a[i]);
            while(l < r) {
                int mid = (l + r) >> 1;
                if(mid + 1 <= r) mid += 1;
                if(Check(mid)) r = mid - 1;
                else l = mid;
            }
            printf("%lld
    ", l);
        }
        return 0;
    }

    F. HDU6235

    签到题。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 200000
    #define int long long
    #define INF 2000000000LL
    int n, k, m, a[maxn], b[maxn], sum[maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    bool Check(int mid) {
        int ans = 0;
        for(int i = 1; i <= n; i ++) 
            if(a[i] >= mid) b[i] = 1;
            else b[i] = 0;
        for(int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + b[i];
        for(int i = 1, j = 0; i <= n; i ++) {
            while(j < n && sum[i] - sum[j] >= k) j ++;
            ans += j;
        }
        return ans < m;
    }
    
    signed main() {
        int T = read();
        while(T --) {
            n = read(), k = read(), m = read();
            int l = INF, r = -INF;
            for(int i = 1; i <= n; i ++) 
                a[i] = read(), l = min(l, a[i]), r = max(r, a[i]);
            while(l < r) {
                int mid = (l + r) >> 1;
                if(mid + 1 <= r) mid += 1;
                if(Check(mid)) r = mid - 1;
                else l = mid;
            }
            printf("%lld
    ", l);
        }
        return 0;
    }

    H.HDU6237

    首先发现最后的x一定是石子总个数的质因子之一,而质因子总数最多不超过20。枚举每一个质因子,将石堆石子个数对 x 取模。之后排序,最优方案一定是把模意义下个数小的石堆的石子往模意义下个数大的石堆上挪。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 500000
    #define MAXN 500000
    #define INF 99999999999999LL
    #define LL long long
    #define int long long 
    int n, tot, cnt, p[maxn], pri[maxn], a[maxn], b[maxn];
    LL sum, ans;
    bool is_pri[maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void Get_Prime() {
        for(int i = 2; i < MAXN; i ++) {
            if(!is_pri[i]) pri[++ tot] = i;
            for(int j = 1; j <= tot; j ++) {
                if(i * pri[j] > MAXN) break;
                is_pri[i * pri[j]] = 1;
                if(!(i % pri[j])) break;
            }
        }
    }
    
    bool Check(LL x) {
        if(x == 1) return 0;
        int X = sqrt(x);
        for(int i = 2; i <= X; i ++)
            if(!(x % i)) return 0;
        return 1;
    }
    
    LL Solve(int p) {
        for(int i = 1; i <= n; i ++) b[i] = a[i] % p;
        sort(b + 1, b + 1 + n);
        LL s = 0, w = 0;
        for(int i = 1, j = n; i <= n && i < j; i ++) {
            w += b[i]; s += b[i];
            while(b[j]) {
                int t = p - b[j];
                if(s >= t) b[j] = p, j --, s -= t;
                else {
                    b[j] += s, s = 0; 
                    break;
                }
            }
        }
        return w;
    }
    
    signed main() {
        int T = read();
        Get_Prime();
        while(T --) {
            n = read(); ans = INF; sum = 0, cnt = 0;
            for(int i = 1; i <= n; i ++) a[i] = read(), sum += (LL) a[i];
            int N = sqrt(sum);
            for(int i = 2; i <= N; i ++) 
                if(!is_pri[i] && !(sum % i)) {
                    p[++ cnt] = i;
                    while(!(sum % i)) sum /= i;
                }    
            if(Check(sum)) p[++ cnt] = sum;
            for(int i = 1; i <= cnt; i ++) {
                ans = min(ans, Solve(p[i]));
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }

    L.HDU6241

    第一个条件子树中至少涂几个点,第二个条件子树外至少涂几个点。二分答案后,这两个条件转化为子树内至少涂几个点,至多涂几个点。树形向上整合区间取交,判断是否出现空集。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 500000
    int n, MID, num[maxn], dp[maxn], size[maxn], a[maxn], b[maxn];
    int L[maxn], R[maxn];
    bool flag;
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    struct edge {
        int head[maxn], to[maxn], last[maxn], cnp = 1;
        void add(int u, int v) {
            to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;
            to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++;
        }
    }E;
    
    void dfs(int u, int fa) {
        size[u] = 1;
        for(int i = E.head[u]; i; i = E.last[i]) {
            int v = E.to[i];
            if(v == fa) continue;
            dfs(v, u);
            size[u] += size[v];
        }
    }
    
    void DP(int u, int fa) {
        L[u] = 0, R[u] = 1;
        for(int i = E.head[u]; i; i = E.last[i]) {
            int v = E.to[i];
            if(v == fa) continue;
            DP(v, u);
            R[u] += R[v];
            L[u] += L[v];
        }
        R[u] = min(R[u], MID - b[u]);
        L[u] = max(L[u], a[u]);
        if(L[u] > R[u] || n - size[u] < b[u]) flag = 0;
    }
    
    bool Check(int mid) {
        flag = 1, MID = mid;
        DP(1, 0);
        if(L[1] > mid || R[1] < mid) flag = 0;
        return flag;
    }
    
    int main() {
        int T = read(); 
        while(T --) {
            n = read(); E.cnp = 1;
            for(int i = 1; i <= n; i ++) E.head[i] = a[i] = b[i] = 0;
            for(int i = 1; i < n; i ++) {
                int u = read(), v = read();
                E.add(u, v); 
            }
            int A = read();
            for(int i = 1; i <= A; i ++) {
                int x = read(), y = read();
                a[x] = max(a[x], y);
            }
            int B = read();
            for(int i = 1; i <= B; i ++) {
                int x = read(), y = read();
                b[x] = max(b[x], y);
            }
            dfs(1, 0);
            int l = 1, r = n;
            while(l < r) {
                int mid = (l + r) >> 1;
                if(Check(mid)) r = mid;
                else l = mid + 1;
            }
            if(Check(0)) printf("0
    ");
            else if(Check(l)) printf("%d
    ", l);
            else printf("-1
    ");
        }
        return 0;
    }

     M.HDU6242

    三点确定一个圆,由于有一半的点都在一个圆上,因此每次随机三个点找到圆的概率很高。

    【一直TLE | WA】咕咕咕

  • 相关阅读:
    Hive创建表格报Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException的错误
    Hive本地模式安装及遇到的问题和解决方案
    CentOS6 编译安装Mysql5.6.26
    数据结构全攻略--学好数据结构的必经之路
    JAVA项目打开出现红色感叹号!
    前端语言html
    1 利用Anaconda完美解决Python 2与python 3的共存问题
    0 Windows上安装Anaconda和python的教程详解
    回溯算法
    建立结构体
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/13743134.html
Copyright © 2020-2023  润新知