• qbxt 10 月模拟赛 Day5


    A

    做法一:答案一定是相邻两个的差的最小值。

    考虑反证法:如果 ([l,r](l+1 < r)) 是答案,那么中间一定能取到一段小于等于平均数的。

    做法二:二分答案。

    首先答案是 (min_{i,j} frac{a_i-a_j}{j-i}),考虑二分最小值,那么相当于对于所有 (j>i) 要有 (a_i-a_j geq kj-ki),也就是 (a_i+k_i geq a_j+k_j),判断是否不增就行。

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 1e5 + 5;
    int n;
    LL a[MAXN];
    
    inline bool chk(LL k){
        FOR(i,2,n){
            if(a[i-1]+k*(i-1) < a[i]+k*i) return 0;
        }
        return 1;
    }
    
    int main(){
        scanf("%d",&n);FOR(i,1,n) scanf("%lld",a+i);
        LL l = 0,r = 2e9,ans = -1;
        while(l <= r){
            LL mid = (l + r) >> 1;
            if(chk(mid)) ans = mid,l = mid+1;
            else r = mid-1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    B

    意思是前 (frac{n}{2}) 是排名前 (frac{n}{2}) 小的,那么标记出来应该移动的点(本来应该在后半部分,但是最初在前半部分),从里向外配对即可。(也考虑跨过每个点的贡献,是两边点的个数的最小值)

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 5e5 + 5;
    
    int a[MAXN],n;
    P b[MAXN];
    bool vis[MAXN];
    
    int main(){
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d",a+i),b[i] = MP(a[i],i);
        std::sort(b+1,b+n+1);
        FOR(i,1,n/2) vis[b[i].se] = 1;
        int tp = 0;FOR(i,n/2+1,n) tp += vis[i];
        LL ans = 0;
        std::vector<int> p1,p2;
        FOR(i,1,n/2) if(!vis[i]) p1.pb(i);
        FOR(i,n/2+1,n) if(vis[i]) p2.pb(i);
        FOR(i,0,tp-1) ans += p2[i]-p1[tp-i-1];
        printf("%lld
    ",ans);
        return 0;
    }
    

    C

    (lcp) 问题,可以考虑建 trie 树,两个串的 (lcp) 就是 (lca)

    然后发现我们在每一个点肯定是尽量匹配子树内的点,所以自下往上贪心即可。注意卡空间,用 map 或者 vector 优化。

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 2e6 + 5;
    int n,k;
    //std::map<int,int> ch[MAXN];
    std::vector<P> ch[MAXN];
    //std::vector<int> ch[MAXN];
    int dep[MAXN];
    char str[100000+5];
    int rt = 1,tot = 1;
    int sm[MAXN];
    
    inline int find(int v,int y){
        for(auto x:ch[v]) if(x.fi == y) return x.se;
        return 0;
    }
    
    inline void insert(char str[]){
        int len = strlen(str+1),v = rt;
        FOR(i,1,len){
            int o = str[i]-'a';
            int t = find(v,o);
            if(!t) ch[v].pb(MP(o,++tot)),dep[tot] = dep[v]+1,t = tot;
            v = t;
        }
        sm[v]++;
    }
    
    LL ans = 0;
    
    inline void dfs(int v){
        for(auto x:ch[v]){
            dfs(x.se);
            sm[v] += sm[x.se];
        }
        ans += dep[v]*(sm[v]/k);
        sm[v] %= k;
    }
    
    int main(){
    //    freopen("C.in","r",stdin);
    //    freopen("C.out","w",stdout);
        scanf("%d%d",&n,&k);
        FOR(i,1,n){
            scanf("%s",str+1);insert(str);
        }
        dfs(1);
        printf("%lld
    ",ans);
        return 0;
    }
    

    D

    比较有意思,但是数据太水了。

    这种东西显然我们有一个单次询问 (O(k^2 log n)) 的做法:转化为 (k^2) 次二维数点。

    那么我们考虑对着根号分治一下:设 (T = sqrt{sum_i k_i}),如果 (k geq T),这样的询问不会有超过 (T) 个,暴力即可。

    如果 (k < T),拆成 (k^2) 个询问,我们来分析下询问次数最大有多少个(我之前一直以为是 (k^2) 个,才发现不是)。

    那么可以使用 (O(T)-O(1)) 的分块技巧实现单点修改,前缀查询,根号平衡后复杂度是 (O(ksqrt k)) 的。

    #pragma GCC optimize("Ofast")
    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 2e5 + 5;
    int n,m,N,q;
    int ans[MAXN];
    
    inline char nc(){
        #define SIZE 1000000+3
        static char buf[SIZE],*p1 = buf+SIZE,*p2 = buf+SIZE;
        if(p1 == p2){
            p1 = buf;p2 = buf+fread(buf,1,SIZE,stdin);
            if(p1 == p2) return -1;
        }
        return *p1++;
        #undef SIZE
    }
    
    template <typename T>
    inline void read(T &x){
        x = 0;int flag = 0;char ch = nc();
        while(!isdigit(ch)){
            if(ch == '-') flag = 1;
            ch = nc();
        }
        while(isdigit(ch)){
            x = (x<<1) + (x<<3) + (ch^'0');
            ch = nc();
        }
        if(flag) x = -x;
    }
    
    struct Node{
        int y;char opt,d;int id;// 0 = mod
    
        Node(int y=0,char opt=0,char d=0,int id=0) : y(y),opt(opt),d(d),id(id) {}
    };
    std::vector<Node> G[MAXN];
    
    int l[MAXN],r[MAXN],B;
    
    inline void add(int x1,int x2,int y1,int y2,int d,int id){
        if(x1 > x2 || y1 > y2) return;
        G[x2].pb(Node(y2,1,1*d,id));
        G[x2].pb(Node(y1-1,1,-1*d,id));
        G[x1-1].pb(Node(y2,1,-1*d,id));
        G[x1-1].pb(Node(y1-1,1,1*d,id));
    }
    
    const int MAXM = 500+5;
    
    struct DS{// O(sqrt(n)) 单点修改 O(1) 查询前缀和
        int B,n;
        int bel[MAXN];
        int sm[MAXM][MAXM],pre[MAXM];
    
        inline void build(int xxx){
            n = xxx;B = std::sqrt(1.0*n);
            FOR(i,1,n) bel[i] = (i-1)/B+1;
        }
    
        inline void add(int pos,int x){
    //        FOR(i,pos,n) pre[i] += x;
    //        return;
            FOR(i,bel[pos]+1,bel[n]) pre[i] += x;
            FOR(i,pos-(bel[pos]-1)*B,bel[pos]*B-(bel[pos]-1)*B) sm[bel[pos]][i] += x;
        }
    
        inline int query(int x){
    //        return pre[x];
            return pre[bel[x]]+sm[bel[x]][x-(bel[x]-1)*B];
        }
    }ds;
    
    bool vis[MAXN];
    int uu[MAXN],vv[MAXN];
    
    int main(){
    //    freopen("D.in","r",stdin);
    //    freopen("D.out","w",stdout);
        read(n);read(m);read(q);
        FOR(i,1,m){
            int u,v;read(u);read(v);
            if(u > v) std::swap(u,v);
            uu[i] = u;vv[i] = v;
            G[u].pb(Node(v,0));
        }
        B = 300;
        FOR(id,1,q){
            int k;read(k);
            if(k >= B){
                FOR(i,1,n) vis[i] = 0;
                FOR(i,1,k){
                    int l,r;read(l);read(r);
                    FOR(j,l,r) vis[j] = 1;
                }
                FOR(i,1,m) ans[id] += vis[uu[i]]&vis[vv[i]];
            }
            else{
                FOR(i,1,k) read(l[i]),read(r[i]);
     //           if(id != 6) continue;
                FOR(i,1,k){
                    FOR(j,i,k){
                        add(l[i],r[i],l[j],r[j],1,id);
                    }
                }
            }
        }
        ds.build(n);
        FOR(i,0,n){
            for(auto x:G[i]){
                if(x.opt == 0) ds.add(x.y,1);
            }
            for(auto x:G[i]){
                if(x.opt == 1) ans[x.id] += x.d*ds.query(x.y);
            }
        }
    //    DEBUG(ans[1]);
        FOR(i,1,q) puts(ans[i]?"GG":"SAFE");
        return 0;
    }
    
  • 相关阅读:
    ubuntu18.04登录界面背景图的更换
    java面向对象基础知识
    java语法+变量
    sql查询
    sql的增删改查
    事件概念和事件监听
    DOM对HTML元素的增删改操作
    DOM对HTML元素访问操作2
    DOM对HTML元素访问操作
    BOM模型中常用对象的介绍
  • 原文地址:https://www.cnblogs.com/rainair/p/14305839.html
Copyright © 2020-2023  润新知