• noip模拟【20190813】


    T1

    [树状数组,线段树]

    暴力O(nm)->60pts

    Noip2018:ans = sigma{max(0,a[i+1]-a[i])};

    令b[i+1] = a[i+1]-a[i];

    区间增加(l,r)只会影响端点(l or r)的b[i]值。

    考虑用树状数组维护答案。

    开两个树状数组,一个记录实际值,一个记录与0相比的较大值

    时间复杂度O(mlogn)

    【code】 

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    #define File "skyscraper"
    inline void file(){
        freopen(File".in","r",stdin);
        freopen(File".out","w",stdout);
    } 
    inline int read(){
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();}
        return x*f;
    }
    const int mxn = 1e5 + 10;
    int n,m;
    int a[mxn],b[mxn];
    
    ll c[mxn][2];
    inline int lowbit(int x){
        return x&(-x);
    }
    inline void update(int x,int d,int k){
        while(x <= n){
            c[x][k] += d;
            x += lowbit(x);
        }
    }
    inline ll query(int x,int k){
        ll ret(0);
        while(x){
            ret += c[x][k];
            x -= lowbit(x);
        } 
        return ret;
    } 
    
    int main(){
        file();
        n = read(),m = read();
        for(int i = 1;i <= n; ++i){ 
            a[i] = read();
            b[i] = a[i]-a[i-1];
            
            update(i,b[i],0);
            if(b[i] > 0) update(i,b[i],1);
        } 
        
        while(m--){ 
            int opt = read(),l = read(),r = read();
            if(opt==1){
                int k = read();
                update(l,k,0),update(r+1,-k,0);        
            
                if(b[l] > 0) update(l,-b[l],1);
                if(b[r+1] > 0) update(r+1,-b[r+1],1);
            
                b[l] += k,b[r+1] -= k;
            
                if(b[l] > 0) update(l,b[l],1);
                if(b[r+1] > 0) update(r+1,b[r+1],1);
                
            }else{
                printf("%lld
    ",query(l,0)+query(r,1)-query(l,1));    
            } 
        }
        return 0;    
    }
    /*
    5 4
    1 3 1 4 5
    2 1 5
    1 3 4 2
    2 2 4
    2 1 5
    */ 
    /*
    7 
    6
    6
    */
    View Code

    T2

    [dfs序]

    找到图中所有叶子节点,求出所有叶子节点的dfs序,这样保证了离得够远,把第i个点连向i+m/2个点时,假如不在一个子树内,形成一个经过root的环。如果它们同时属于一个子树,那么说明这个子树很大,一定可以有一个属于这个子树的叶子连到别的子树中去。

    【code】 

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    #define File "network"
    inline void file(){
        freopen(File".in","r",stdin);
        freopen(File".out","w",stdout);
    } 
    inline int read(){
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();}
        return x*f;
    }
    const int mxn = 1e5+5;
    int n,m,h;
    struct edge{
        int y,nxt;
    }e[mxn<<1];
    
    int to[mxn],len;
    inline void add(int xx,int yy){
        e[++len].nxt = to[xx];
        to[xx] = len;
        e[len].y = yy;
    }
    
    struct P{
        int id,dfn;
    }p[mxn];
    
    inline bool cmp(P t1,P t2){
        return t1.dfn < t2.dfn;
    }
    
    int rt;
    int b[mxn],deg[mxn];
    int tot(0);
    
    int dfn[mxn];
    void dfs(int x,int fa){
        dfn[x] = ++tot;
        for(int i = to[x]; i;i = e[i].nxt){
            int y = e[i].y;
            if(y == fa) continue;
            dfs(y,x);
        }
    }
    
    int main(){
    //    file();
        n = read(),h = read();
        for(int i = 1;i < n; ++i){
            int x = read(),y = read();
            deg[x]++,deg[y]++;    
            add(x,y),add(y,x);
        }
    
        tot = 0;
        dfs(h,-1);
        
        tot = 0;
        for(int i = 0;i < n; ++i){
            if(!deg[i])
                p[++tot].id = i,p[tot].dfn = dfn[i];
        } 
        sort(p+1,p+tot+1,cmp);
    
        printf("%d
    ",(tot+1)/2);
        for(int i = 1;i <= tot/2; ++i) 
            printf("%d %d
    ",p[i].id,p[i+tot/2].id);        
        if(!(tot&1)) printf("%d %d
    ",p[1].id,p[tot].id);
        return 0;
    }
    /*
    4 0
    0 1
    0 2
    0 3
    */
    View Code

    T3

    [dp]

    交换k次路灯的操作就是将没有选的集合中挑出代价最小的不超过k个代价,替换掉已选集合中较大的几个代价。

    贪心:

    或者说,选的集合要么是2、5、8… (%3==1)+1

    要么是1、4、7…(%3==0)+1

    好,上面那个做法假了。

    交换的一定是一盏亮的灯和一盏灭的灯。

    设f[i][x][y][a][b]表示考察前i盏灯,最后两盏灯的亮灭状态为x、y,已经有a盏亮的灯被换走,已经有b盏灭的灯被换上去的最小代价。

    几种转移,点灯,不点灯,点亮后被换走,不点从别的地方

    如果x,y都是亮着的,f[i][y][0][a][b] = min(f[i][y][0][a][b],f[i-1][x][y][a][b]);

    如果灭的灯还能被换上去,f[i][y][1][a][b+1] = min(f[i][y][1][a][b+1],f[i-1][x][y][a][b]);

    如果亮着的灯还没被换走,而且前两盏灯都是亮的,

    f[i][y][0][a+1][b] = min(f[i][y][0][a+1][b],f[i-1][x][y][a][b]+val);

     【code】

    #include <bits/stdc++.h>
     
    using namespace std;
     
    const int K = 10;
    const int N = 2.5e5 + 5;
    const long long INF = 1e17;
     
    int n, k;
    int w[N];
    long long dp[2][2][2][K][K];
     
    bool Chkmin(long long &a, long long b) {
        return (a > b)? (a = b, 1) : (0);
    //    if(a>b) a = b, return 1;
    //    else return 0
    }
    
    
    inline int read(){   
        int num = 0; bool f = 1;char ch = getchar();   
        while(ch < '0' || ch > '9') { if(ch == '-') f = 0;ch = getchar();}   
        while(ch >= '0' && ch <= '9') {num = num * 10 + ch - '0';ch = getchar();}   
        return num = f ? num: -num;   
    } 
     
    int main() {
        freopen("light.in","r",stdin);
        freopen("light.out","w",stdout);
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; ++i) {
          w[i] = read();
        }
        
        memset(dp, 0x3f, sizeof dp);
        dp[0][1][0][0][0] = 0;
        for (int i = 0; i < n; ++i) {
          int nxt = ~i & 1, pre = i & 1, val = w[i + 1];
          memset(dp[nxt], 0x3f, sizeof dp[nxt]);
          for (int a = 0; a <= k; ++a) { 
            for (int b = 0; b <= k; ++b) { 
              for (int x = 0; x < 2; ++x) {
                for (int y = 0; y < 2; ++y) {
                    if (dp[pre][x][y][a][b] > INF) continue;
                    Chkmin(dp[nxt][y][1][a][b], dp[pre][x][y][a][b] + val);
                    if (x || y)
                      Chkmin(dp[nxt][y][0][a][b], dp[pre][x][y][a][b]);
                    if (b < k)
                      Chkmin(dp[nxt][y][1][a][b + 1], dp[pre][x][y][a][b]);
                    if (a < k && (x || y))
                      Chkmin(dp[nxt][y][0][a + 1][b], dp[pre][x][y][a][b] + val);
                }
              }
            }
          }
        }
     
        long long ans = INF;
        for (int i = 0; i <= k; ++i) {
          for (int x = 0; x < 2; ++x) {
            for (int y = 0; y < 2; ++y) {
              if (x || y) {
                  ans = min(ans, dp[n & 1][x][y][i][i]);
              }
            }
          }
        }
     
        printf("%lld
    ", ans);
      
        return 0;
    }
    View Code
  • 相关阅读:
    面试40-一个数组,有2个数字出现奇数次,其余都是偶数次,求这两个数字O(n) O(1)
    面试38-数字在排序数组中出现的个数
    面试35-删除字符串重复字符-删除出现在第二个字符串中的字符-第一个只出现一次的字符-hash表计数
    意外get接近完美的黑苹果 (UEFI + GPT)
    Windows 启用/禁用内置管理员 Administrator
    出去走走
    【搬运】Wget 命令详解
    C语言学习之插入排序
    由 UWP 版网易云音乐闪退引发的博文
    gets() 与 scanf() 的小尴尬
  • 原文地址:https://www.cnblogs.com/ve-2021/p/11379700.html
Copyright © 2020-2023  润新知