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\n",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\n",(tot+1)/2);
    for(int i = 1;i <= tot/2; ++i) 
        printf("%d %d\n",p[i].id,p[i+tot/2].id);        
    if(!(tot&1)) printf("%d %d\n",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\n", ans);
  
    return 0;
}
View Code

 

posted @ 2019-08-19 21:03  ve-2021  阅读(157)  评论(0编辑  收藏  举报