zoukankan      html  css  js  c++  java
  • 暑假第二十五测

    以后WA了T了看数组;

    暑假四次数组下标超界,多次数组开小,暂时没有访问到负下标

    题解;

    第一题;这道题可以转换为颜色相同的点缩成一个点,每次可以将两个点合并成同一点,问最少几次将所有点合并成一个点;

    开始想到并查集+贪心合并度数最多的并查集,但这样是有问题的,比如度数一样时,选择的先后顺序是有影响的;

    正解:缩点+找直径,如果是一条黑白相间的链,就是点数/2, 而树上任何一条直径都会有一个点经过直径,我们从交点开始往外延伸,发现最长延伸就是直径本身;

    思想:从特殊到一般

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 1e5 + 10;
    #define ex(i, u) for(int i = h[u]; i; i = G[i].nxt)
    int h[M], col[M], tot, fa[M], rec[M], vec[M], dep[M];
    struct edge{int nxt, v;}G[M * 2];
    void add(int u, int v){
        G[++tot].nxt = h[u]; h[u] = tot; G[tot].v = v;
    }
    int find(int u){
        if(u == fa[u])return u;
        return fa[u] = find(fa[u]);
    }
    void uni(int u, int v){
        fa[find(u)] = find(v);
    }
    int read(){
        int x = 0,f = 1; char c = getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*=f;
    }
    int rt, res;
    void dfs(int u, int f){
        //fprintf(stderr , "%d %d
    ", u, f);
        dep[u] = dep[f] + 1; 
        ex(i, u){
            int v = G[i].v;
            if(v == f)continue;
            dfs(v, u);
        }
        if(dep[u] > dep[res])res = u;
    }
    
    
    int main(){
        freopen("color.in","r",stdin);
        freopen("color.out","w",stdout);
        int T;
        scanf("%d", &T);
        while(T--){
            int n = read();    
            for(int i = 1; i <= n; i++)
                col[i] = read(), h[i] = 0, fa[i] = i;
            tot = 0;
            int u, v, p = 0;
            for(int i = 1; i < n; i++){
                u = read(), v = read();
                if(col[u] == col[v])uni(u, v);
                else vec[++p] = u, rec[p] = v;
            }
            for(int i = 1; i <= p; i++){
                int x = find(rec[i]), y = find(vec[i]);
                add(x, y), add(y, x); //fprintf(stderr, "%d %d
    ", y, x);
            }
            for(int i = 1; i <= n; i++)
                if(i == find(i)){
                    res = rt = 0;
                    memset(dep, 0, sizeof(dep));
                    dfs(i, 0);
                    memset(dep, 0, sizeof(dep));
                    rt = res;
                    dfs(rt, res = 0);
                    break;
                }
            printf("%d
    ", dep[res]/ 2);
        }
        return 0;
    }
    View Code

    第二题:模拟,我们发现很多路径是重复的,所以要想办法避免;又发现格子最多有150^2个,所以我们只需要记录格子是否被访问;每次从一个格子暴力沿八个方向走,如果到一个格子也有相同的方向,如果该格子走的远,就停下来,让这个格子完成任务,如果该格子走的不如当前远,那么他的延伸就是废的,去掉;

    每个格子最多朝8个方向时被重复,就是O(300*300*8);

    这道题我数组开的N,循环的时候也循环到N, 开了O2全WA,都学这么久了,怎么还在犯这种低级错误!!!

    而且上次考试又是少写了一个等号全WA!!!该好好练练码力了;

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 306;
    int zl[10][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}};
    int go[10][2] = {{0, 0}, {2, 8}, {1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {6, 8}, {1, 7}};
    int n;
    int mp[N+11][N+11][10], a[50];
    bool vis[N+11][N+11], done[N+11][N+11];
    struct node{int x,y,dep,fx;};
    void bfs(){
        queue <node> q;
        q.push((node){152, 152, 1, 1});
        mp[152][152][1] = 1;
        
        while(!q.empty()){
            node u = q.front(); q.pop();
            done[u.x][u.y] = 1;
            int i = u.fx;
            int x = u.x + zl[i][0] * a[u.dep], y = u.y + zl[i][1] * a[u.dep];
            if(a[mp[x][y][go[i][0]]] < a[u.dep + 1]){
                mp[x][y][go[i][0]] = u.dep + 1;q.push((node){x, y, u.dep + 1, go[i][0]});
            }
            if(a[mp[x][y][go[i][1]]] < a[u.dep + 1]){
                mp[x][y][go[i][1]] = u.dep + 1;q.push((node){x, y, u.dep + 1, go[i][1]});
            }        
        }
    }
    
    void work(){
        for(int i = 1; i <= N; i++)
            for(int j = 1; j <= N; j++){
                if(!done[i][j])continue;
                for(int k = 1; k <= 8; k++){
                    if(mp[i][j][k]){
                        //printf("%d %d %d %d
    ", i, j, k, mp[i][j][k]);
                        int x = i, y = j;
                        for(int z = 1; z <= a[mp[i][j][k]]; z++){
                            x += zl[k][0], y += zl[k][1];
                            if(a[mp[x][y][k]] > a[mp[i][j][k]] - z)break;
                            else mp[x][y][k] = 0;
                            vis[x][y] = 1;
                        }
                        vis[i][j] = 1;
                    }
                }
            }
                
    }
    
    
    int main(){
        freopen("grow.in","r",stdin);
        freopen("grow.out","w",stdout);
        //int cc=clock();
        int ans = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)scanf("%d", &a[i]);
        a[1]--;
        bfs();
        work();
        for(int i = 1; i <= N; i++)
            for(int j = 1; j <= N; j++)if(vis[i][j])ans++;//,printf("%d %d
    ",i,j);
        printf("%d
    ", ans);
        //int tt=clock();
        //cout<<tt-cc;
    }
    View Code

    第三题:dp,定义状态 :

    0  1    2        3         4

    #  2    20    201    2017

    dp[s][t]表示从状态s转移到状态t的最少删除字符,我们枚举中间状态r, dp[s][t] = min(dp[s][r] + dp[r][t]);

    但不可能每次询问都做一次,所以用线段树做,转移相当于线段树合并;代码可以学习一下

    #include<bits/stdc++.h>
    using namespace std;
    const int inf = 1e8, M = 1e5 + 10;
    int n;
    char s[M];
    struct Info{//没有放在Node里是因为重载运算符不能返回一个指针 
        int tr[5][5];
        // 0 1  2  3   4 
        // $ 2 20 201 2017
        void init(int v){
            memset(tr, 0x3f, sizeof(tr));
            if(v == 3 || v == 4 || v == 5 || v == 8 || v == 9){
                for(int i = 0; i < 5; i ++)tr[i][i] = 0;
            }
            
            if(v == 2){
                tr[0][0] = 1;
                tr[0][1] = 0;
                tr[1][1] = tr[2][2] = tr[3][3] = tr[4][4] = 0;
            }
            
            if(v == 0){
                tr[1][2] = 0;
                tr[1][1] = 1;
                tr[0][0] = tr[2][2] = tr[3][3] = tr[4][4] = 0;
            } 
            
            if(v == 1){
                tr[2][3] = 0;
                tr[2][2] = 1;
                tr[0][0] = tr[3][3] = tr[4][4] = tr[1][1] = 0;
            }
            
            if(v == 7){
                tr[3][3] = 1;
                tr[3][4] = 0;
                tr[1][1] = tr[4][4] = tr[2][2] = tr[0][0] = 0;
            }
            
            if(v == 6){
                tr[3][3] = tr[4][4] = 1;
                tr[0][0] = tr[1][1] = tr[2][2] = 0;
            }
        }
    };
    struct Node{
        Info info;
        Node *ls, *rs;
    }pool[(M << 2)], *tail = pool, *root; 
    
    Info operator + (const Info &a, const Info &b){//重载运算符写法 
        Info rt;
        memset(&rt, 0x3f, sizeof(rt));//取地址 
        for(int i = 0; i < 5; i++)
            for(int j = 0; j < 5; j++)
                for(int k = i; k <= j; k++)
                    rt.tr[i][j] = min(rt.tr[i][j], a.tr[i][k] + b.tr[k][j]);
        /*for(int i = 0;i<5;i++)for(int j=0; j<5;j++)
        printf("%d %d %d
    ",i,j,zero->tr[i][j]);puts("");*/
        return rt;
    }
    
    Node * build(int lf = 1, int rg = n){
        Node *nd = ++tail;
        if(lf == rg)nd->info.init(s[lf - 1] - '0');
        else {
            int mid = (lf + rg) >> 1;
            nd->ls = build(lf, mid);
            nd->rs = build(mid + 1, rg);
            nd->info = nd->ls->info + nd->rs->info;
        }
        return nd;
    }
     
    Info query(int L, int R, Node * nd = root, int lf = 1, int rg = n){
        if(lf >= L && rg <= R)return nd->info;
        int mid = (lf + rg) >> 1;
        if(L > mid)return query(L, R, nd->rs, mid + 1, rg);
        else if(R <= mid)return query(L, R, nd->ls, lf, mid);
        else return query(L, R, nd->ls, lf, mid) + query(L, R, nd->rs, mid + 1, rg);
    }
    int Query(int l, int r){
        Info ans = query(l, r);
        return ans.tr[0][4] < inf ? ans.tr[0][4] : -1;
    }
    
    int main(){
        freopen("year.in","r",stdin);
        freopen("year.out","w",stdout);
        scanf("%s", s);
        n = strlen(s);
        root = build();
        int q, l, r;
        scanf("%d", &q);
        while(q--){
            scanf("%d%d", &l, &r);
            printf("%d
    ", Query(l, r));
        }
        
    }
    View Code
  • 相关阅读:
    DevOps
    DevOps
    微信的NATIVE支付提示201商户订单号重复的解决方案
    phpstorm 破解
    Git忽略已经被版本控制的文件(添加.gitignore不会起作用)
    微信 {"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: 1QoCla0699ns81 ]"}
    如何用AJax提交name[]数组?
    基于PHP给大家讲解防刷票的一些技巧
    为何GET只发一次TCP连接,POST发两次TCP连接
    IP地址在mysql的存储(IP地址和int的转换)
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9538252.html
Copyright © 2011-2022 走看看