zoukankan      html  css  js  c++  java
  • qbxt 10 月模拟赛 Day2

    总算是正常的普及组模拟赛难度了。。昨天的甚至算不上普及组模拟赛难度吧(

    A

    二分答案,我们肯定是贪心等到必须要选取某个点的时候再选取。

    可以每次二分判断,也可以开个指针维护中位数在哪里来判断。

    #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,k;LL a[MAXN];
    int f[MAXN];
    
    inline int get(int l,int r){
        if(l+1 >= r) return 0;
        LL mid = (a[l] + a[r]) >> 1;
        int p = std::lower_bound(a+l,a+r+1,mid)-a;
        LL ans = 0;
        FOR(i,p-1,p+1) if(i >= l && i <= r) ans = std::max(ans,std::min(a[i]-a[l],a[r]-a[i]));
        return ans;
    }
    
    inline bool chk(LL k){
        f[0] = 0;f[1] = 1;
        int p = 1;
        FOR(i,2,n){
            if(a[i]-a[1] <= k) f[i] = 1;
            else f[i] = 1e9;
            while(p <= i && get(p,i) > k) ++p;
            f[i] = std::min(f[i],f[p]+1);
        }
        int ans = 1e9;
        ROF(i,n,1){
            if(a[n]-a[i] <= k) ans = std::min(ans,f[i]);
        }
        return ans <= ::k;
    }
    
    int main(){
        scanf("%d%d",&n,&k);
        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,r = mid-1;
            else l = mid+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    B

    模拟一下 (n=6) 的过程:

    1 2 3 4 5 6
    2 1 4 3 6 5
    1 4 2 6 5 3
    4 2 6 1 3 5
    2 6 1 3 4 5
    6 1 3 4 5 2
    

    看起来毫无规律,但是我们观察发现每次移动后在每一组开头的数都会移动,其他的数单调减一,会空出来若干个空,我们可以将这些数直接填到空里。

    这种题我们考虑向右移动一位,那么其他数就是不变。

    1 2 3 4 5 6
      2 1 4 3 6 5
        1 4 2 6 5 3
          4 2 6 1 3 5
            2 6 1 3 4 5
              6 1 3 4 5 2
    

    发现相当于不同的数都往后移动了一位,直接模拟即可。

    现在有一种形象的理解:每次将移动的位置全都往后统一移动。

    [1] 2 [3] 4 [5] 6
        2 [1] 4 [3] 6 [5]
    
    #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 = 1e6 + 5;
    int n;
    int a[MAXN<<1];
    
    int main(){
        scanf("%d",&n);
        FOR(i,1,n) a[i] = i;
        FOR(i,2,n){
            int t = 0;
            for(int j = i-1;j <= i-1+n-1;j += i){
                std::swap(t,a[j]);
            }
            std::swap(t,a[i-1+n]);
        }
        FOR(i,n,n+n-1) printf("%d ",a[i]);puts("");
        return 0;
    }
    

    C

    (f_{i,j}) 表示考虑了前 (i) 个位置,最后一次选在 (i) 上,选了 (j) 个灯的方案数。预处理一下 (g_{i,j}) 表示选了 (i,j) 但是没有选中间的灯的代价,就可以 (O(n^2k)) 转移了。

    据说这个东西满足四边形不等式,所以可以决策单调性优化。考试的时候比较懒,没有预处理,因为常数很小所以效果很好。

    #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 = 200+5;
    const int MAXM = 30 +5;
    int n,k;
    LL f[MAXN][MAXM];
    LL a[MAXN];
    LL suf[MAXN];
    
    int main(){
        scanf("%d%d",&n,&k);
        FOR(i,1,n) scanf("%lld",a+i);a[0] = -1e18;
        ROF(i,n,1) suf[i] = suf[i+1]+a[i];
        CLR(f,0x3f);
        f[0][0] = 0;
        FOR(i,1,n){
            FOR(j,1,std::min(i,k)){
                FOR(k,0,i-1){
                    LL gx = 0;
                    FOR(l,k+1,i-1){
                        gx += std::min(a[l]-a[k],a[i]-a[l]);
                    }
                    f[i][j] = std::min(f[i][j],f[k][j-1]+gx);
                }
            }
        }
        LL ans = 1e18;
        FOR(i,1,n){
            ans = std::min(ans,f[i][k]+suf[i+1]-(n-i)*a[i]);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    D

    发现所有的组合一定满足形如一个中心点连出去三条链。

    所以对于每个点预处理出距离这个点为 (2) 的点的点权和,平方和,立方和,就可以容斥求出答案。

    sb出题人造的"树"让我少了 (40) + 调了一中午。。原因是他们写的是 dfs 只算了一个连通块。。

    #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;
    LL a[MAXN];int n;
    
    struct Edge{
        int to,nxt;
    }e[MAXN<<1];
    int head[MAXN],cnt;
    
    inline void add(int u,int v){
        e[++cnt] = (Edge){v,head[u]};head[u] = cnt;
        e[++cnt] = (Edge){u,head[v]};head[v] = cnt;
    }
    
    LL f[MAXN][4],g[MAXN][4];
    
    inline LL calc(LL s1,LL s2,LL s3){
        return s1*s1*s1-s2*s1*3+s3*2;
    }
    
    inline LL calc2(LL s1,LL s2){
        return s1*s1-s2;
    }
    
    int main(){
        scanf("%d",&n);
        FOR(i,1,n) scanf("%lld",a+i);
        FOR(i,2,n){
            int u,v;scanf("%d%d",&u,&v);
            add(u,v);
        }
        FOR(v,1,n) for(int i = head[v];i;i = e[i].nxt){
            LL val = a[e[i].to];
            FOR(j,1,3){
                f[v][j] += val;
                val = val*a[e[i].to];
            }
        }
        FOR(v,1,n) for(int i = head[v];i;i = e[i].nxt){
            g[v][1] += f[e[i].to][1]-a[v];
            g[v][2] += f[e[i].to][2]-a[v]*a[v];
            g[v][3] += f[e[i].to][3]-a[v]*a[v]*a[v];
        }
        LL ans = 0;
        FOR(i,1,n) ans += calc(g[i][1],g[i][2],g[i][3]);//,DEBUG(calc(g[i][1],g[i][2],g[i][3]));
        FOR(v,1,n){
            LL gx = 0,sm = 0;
            for(int i = head[v];i;i = e[i].nxt) sm += f[e[i].to][1]-a[v];
            for(int i = head[v];i;i = e[i].nxt){
                gx += calc(f[e[i].to][1]-a[v],f[e[i].to][2]-a[v]*a[v],f[e[i].to][3]-a[v]*a[v]*a[v]);
                ans -= calc(f[e[i].to][1]-a[v],f[e[i].to][2]-a[v]*a[v],f[e[i].to][3]-a[v]*a[v]*a[v]);
                LL t = calc2(f[e[i].to][1]-a[v],f[e[i].to][2]-a[v]*a[v]);
                sm -= f[e[i].to][1]-a[v];
                ans -= t*sm*3;
                sm += f[e[i].to][1]-a[v];
            }
    //        DEBUG(gx);
        }
    //    assert(ans%6==0);
        ans /= 6;
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    关于http协议详解
    python记录_day15 面向对象初识
    python记录_day14 内置函数二 迭代 二分法
    python记录_day13 内置函数
    python记录_day12 生成器
    python记录_day11 闭包 迭代器
    函数默认参数的初始化问题
    python记录_day10 动态传参 命名空间 作用域
    python记录_day09 初识函数
    python记录_day08
  • 原文地址:https://www.cnblogs.com/rainair/p/14305845.html
Copyright © 2011-2022 走看看