zoukankan      html  css  js  c++  java
  • 平时六测

    第一题:抽屉原理,维护前缀和,出现一样的中间就可以了;

    我看成了不能选一样的数(其实我觉得题意有歧义,也可能是我太久没学语文了),难度翻翻,以后要认真审题;

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 1000005;
    bool dp[M];
    
    int a[M], sum[M], ap[M];
    int main(){
        freopen("set.in","r",stdin);
        freopen("set.out","w",stdout);
        int n, x, ans = -1, cnt = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
        }
        memset(ap, -1, sizeof(ap));
        ap[0] = 0;
        for(int i = 1; i <= n; i++){
            sum[i] = (sum[i - 1] + a[i]) % n;
            if(ap[sum[i]] != -1) {
                printf("%d
    ", i - ap[sum[i]]);
                for(int j = ap[sum[i]] + 1; j <= i; j++){
                    printf("%d ", j);
                }
                break;
            }
            else ap[sum[i]] = i;
        } 
        
    } 
    View Code

    第二题:空间问题,思路贪心,只要 max <= (n + 1)  /  2就可以全部选择;

    不能用数组记录种类,采用抵消思想 ;

    扫的时候记录一个id, cnt;

    if  cnt = 0,    id = a[i], cnt = 1;

    else if a[i] = id, cnt++

    else cnt--;

    最后跑出来的id是一个理想最大值;

    如果 max > (n + 1) / 2, 那么id一定是种类最多的那个数, 这个采用抵消思想易证;

    如果 max < (n + 1) / 2, id不一定是个数最多的那个数,但这不影响答案;

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int M = 1005;
    int ct[M];
    ll X[M], Y[M], Z[M]; 
    int main(){
        freopen("read.in","r",stdin);
        freopen("read.out","w",stdout);
        int N, S, M, K, ret = 0, cnt = 0;
        scanf("%d%d", &M, &K);
        for(int i = 1; i <= M; i++)scanf("%d", &ct[i]), ret += ct[i];
        for(int i = 1; i <= M; i++)scanf("%lld", &X[i]);
        for(int i = 1; i <= M; i++)scanf("%lld", &Y[i]);
        for(int i = 1; i <= M; i++)scanf("%lld", &Z[i]);
        N = 0, S = (1 << K) - 1;
        ll qlst = -1;
        for(int i = 1; i <= M; i++){
            N++;
            if (cnt==0) qlst = X[i] ,cnt = 1;
            else if (X[i] == qlst) cnt++;
            else cnt--;
            
            ll lst = X[i];
            for(int j = 1; j < ct[i]; j++){
                lst = (lst * Y[i] + Z[i]) & S;
                N++;
                if (cnt==0) qlst = lst ,cnt = 1;
                else if (lst == qlst) cnt++;
                else cnt--;
            }
        }
        
        cnt = 0;
        N = 0, S = (1 << K) - 1;
        for(int i = 1; i <= M; i++){
            N++;
            ll lst = X[i];
            if(qlst == X[i]) cnt++;
            for(int j = 1; j < ct[i]; j++){
                lst = (lst * Y[i] + Z[i]) & S;
                N++;
                cnt += (lst == qlst); 
            }
        }
        if(cnt > (ret + 1)/2) printf("%d
    ", cnt - (ret - cnt) - 1);
        else puts("0");
        
        
    }
    View Code

    第三题:Trie树, 按照每个人的得分建一棵深度为m的Trie树;

     我们在Trie树上跑一个人积分的总和, 我们先按原数跑,假设现在的深度是dep,他当前排在前面,那么当 j 的这一位(dep位)改变时,这颗子树中每个排名都会整体往后降size[now]位, 而内部的相对排名是不变的;

    我们记录P为当前节点中积分和 P = a1^2 + a2^2 + a3^2 +……

    令S= siz[now], 那么另一个节点 P = (a1 + S) ^2 + (a2 + S)^2 + (a3 + S)^2 + ……

    我们合并子树 P = P + P + (a1 + a2 + a3 + ……) * 2 * S + S*S * 2^(dep - 1)   (这个节点下有(2^(dep-1))场比赛;

    用 sum = a1 + a2 + a3 + ……

    所以 sum = sum * 2 + S * 2^(dep-1), P = 2 * P + 2 * S * sum + S*S * 2^(dep - 1)

    #include<bits/stdc++.h>
    using namespace std;
    #define ss siz[ch[now][t^1]]
    #define ll long long
    const int M = 200005, ME = 5*1e6;
    const ll mod = 1e9 + 7;
    int a[M], tot;
    ll bin[M], siz[ME];
    int ch[ME][2], n, m;
    
    void insert(int x){
        int now = 0;
        for(int i = m; i >= 1; i--){
            int t = bin[i-1] & x ? 1 : 0;
            if(!ch[now][t]) ch[now][t] = ++tot;
            now = ch[now][t];
            siz[now]++;
        }
    }
    struct Node{ll sum, q;}; 
    Node query(int x, int dep, int now){
        if(!dep) return (Node) {0, 0};
        int t = bin[dep - 1] & x ? 1 : 0;
        Node rs = query(x, dep - 1, ch[now][t]);
        ll sum = (rs.sum * 2 % mod + ss * bin[dep - 1] % mod) % mod;
        ll q = (rs.q * 2 % mod + 2 * rs.sum * ss % mod + ss * ss % mod * bin[dep - 1] % mod ) % mod;
        
        return (Node) {sum, q};
    }
    int main(){
        freopen("race.in","r",stdin);
        freopen("race.out","w",stdout);
        
        scanf("%d%d", &n, &m);
        bin[0] = 1;
        for(int i = 1; i <= 31; i++) bin[i] = (bin[i - 1] << 1) % mod;
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
            insert(a[i]); 
        } 
        ll ans = 0;
        for(int i = 1; i <= n; i++){
            Node p = query(a[i], m, 0);
            //printf("%lld %lld
    ", p.sum, p.q);
            ans = ans ^ p.q;
        }
        printf("%lld
    ", ans);
    } 
    View Code
  • 相关阅读:
    多重背包POJ1276不要求恰好装满 poj1014多重背包恰好装满
    哈理工1053完全背包
    求最小公倍数与最大公约数的函数
    Bus Pass ZOJ 2913 BFS 最大中取最小的
    POJ 3624 charm bracelet 01背包 不要求装满
    HavelHakimi定理(判断一个序列是否可图)
    z0j1008Gnome Tetravex
    ZOJ 1136 Multiple BFS 取模 POJ 1465
    01背包 擎天柱 恰好装满 zjut(浙江工业大学OJ) 1355
    zoj 2412 水田灌溉,求连通分支个数
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9693238.html
Copyright © 2011-2022 走看看