18.8.26 考试总结

我真的服了 我考试的时候这道题题都是读错了的 交了个挖挖机结果还狗了20分..

这道题是一道找规律的题 看完题很显然能够发现我们可以将相同颜色的连通块缩点

因为同一个联通块的可以一次操作全部变成另外一种颜色 所以就缩点就好了..

对于缩点后的一条链

每次我们可以将一个点变色 那么和他相邻的点就和他颜色一样 然后就再次缩点 所以每次链的长度都可以 -2

所以说最后缩点的次数就是  点的个数 / 2  (下取整)

但是这是对于一条链 那么对于一棵树而言呢?

其实是一样的 因为每次搞这个操作 我们都可以把它周围的点都缩起来 那么对于多条链的情况

每次就选择两链的交点进行这个操作 经过这个点的所有链长度均 - 2  所以操作次数就是最长链 也就是直径的点数 / 2(下取整)

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int n,c[N],node,T,tot,head[N],nex[2 * N],tov[2 * N];
int id[N],fa[N],dis[N],ma,ev[N],eu[N],cnt;
bool vis[N];
queue<int>Q;

int find_fa(int u) {

    return u == fa[u] ? u : find_fa(fa[u]);
}

void merge(int u,int v) {

    int fa1 = find_fa(u);
    int fa2 = find_fa(v);
    if(fa1 == fa2) return ;
    fa[fa2] = fa1;
}

void add(int u,int v) {

    tot ++;
    nex[tot] = head[u];
    tov[tot] = v;
    head[u] = tot;
}

void bfs(int st) {

    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[st] = 0; vis[st] = true;
    node = st,ma = 0;
    Q.push(st);
    while(! Q.empty( )) {
        int u = Q.front( ); Q.pop( );
        for(int i = head[u];i;i = nex[i]) {
            int v = tov[i];
            if(vis[v]) continue;
            vis[v] = true;
            dis[v] = dis[u] + 1;
            if(dis[v] > ma) {
                ma = dis[v];
                node = v;
            }
            Q.push(v);
        }
    }
    return ;
}

void init( ) {

    memset(head,0,sizeof(head));
    tot = 0;
    for(int i = 1;i <= n;i ++) fa[i] = i;
}

int main( ) {

    freopen("color.in","r",stdin);
    freopen("color.out","w",stdout);
    scanf("%d",& T);
    while(T --) {
        scanf("%d",& n);
        init( );
        for(int i = 1;i <= n;i ++) scanf("%d",& c[i]);
        for(int i = 1;i < n;i ++) {
            scanf("%d%d",& eu[i],& ev[i]);
            if(c[eu[i]] == c[ev[i]]) {
                merge(eu[i],ev[i]);
            }
        }
        for(int i = 1;i < n;i ++) {
            int f1 = find_fa(eu[i]),f2 = find_fa(ev[i]);
            if(f1 != f2) {
                if(! id[f1]) {
                    id[f1] = ++ cnt;
                }
                if(! id[f2]) {
                    id[f2] = ++ cnt;
                }
                add(id[f1],id[f2]);
                add(id[f2],id[f1]);
            }
        }
        bfs(1);
        bfs(node);
        printf("%d\n",(dis[node] + 1)/2);
    }
}

考试的时候打得垃圾暴力狗了30

这道题是一道bfs模拟 题 因为t很小 所以可以发现从初始点(175,175)出发的点范围肯定在(400,400)以内

每一个状态可以拓展出的状态很多 所以会出现很多重复的状态 拓展过的状态就不用重新再计算了

所以就开一个vis数组表示这个情况是否被拓展过 然后就很简单了

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int dp[400][400],t[N],h[2] = {-1,1},n,ans = 0;
bool vis[400][400][40][8];
struct node {

    int x,y,s,d;
    node(){}
    node( int x, int y, int s, int d ):x(x),y(y),s(s),d(d){}
}stat;
int dx[] = {0,-1,-1,-1,0,1,1,1};
int dy[] = {1,1,0,-1,-1,-1,0,1};
queue<node>Q;

void bfs( ) {

    while(! Q.empty()) {
        node u = Q.front( );
        Q.pop( );
        int xx = u.x,yy = u.y,dep = u.s;
        if(dep == n) continue;
        for(int i = 0;i <= 1;i ++) {
            int dd = ((u.d + h[i]) % 8 + 8) % 8;
            for(int j = 1;j <= t[dep + 1];j ++) {
                xx += dx[dd]; yy += dy[dd];
                dp[xx][yy] = 1;
            }
            if(! vis[xx][yy][dep + 1][dd]) {
                vis[xx][yy][dep + 1][dd] = true;
                Q.push(node(xx,yy,dep + 1,dd));
            }
            xx = u.x,yy = u.y;
        }
    }
    for(int i = 0;i < 400;i ++)
      for(int j = 0;j < 400;j ++)
        ans += dp[i][j];
}

int main( ) {

    freopen("grow.in","r",stdin);
    freopen("grow.out","w",stdout);
    scanf("%d",& n);
    for(int i = 1;i <= n;i ++) scanf("%d",& t[i]);
    for(int i = 1;i <= t[1];i ++) {
        dp[175][174 + i] = true;
    }
    vis[175][174 + t[1]][1][0] = true;
    Q.push(node(175,174 + t[1],1,0));
    bfs( );
    printf("%d",ans);
}

这道题可以转化为类似于状态合并的问题   共有5个状态  空集 2 20 201 2017

tr[ i ][ j ]表示从 i 号状态转移到 j 号状态 最少需要删掉多少字符

那么类似于Floyd 对于两个区间 a b及他的左右两个区间

tr[ i ][ j ] = min(tr[ i ][ k ] + tr[ k ][ j ]) 总的状态可以由他的两个连续子状态转移过来

但是每次都去暴力搞就很糟糕 所以考虑用线段树维护就可以了

代码

#include <bits/stdc++.h>
#define oo 0x3f
using namespace std;

const int N = 2e5 + 5;
int n,a[N],q;
char s[N];
struct Info {

    int tr[5][5];
    void init(int cur) {
        memset(tr,0x3f,sizeof(tr));
        if(cur == 3 || cur == 4 || cur == 5 || cur == 8 || cur == 9) {
            for(int i = 0;i <= 4;i ++) tr[i][i] = 0;
        }
        if(cur == 2) {
            tr[0][0] = 1;
            tr[0][1] = 0;
            tr[1][1] = tr[2][2] = tr[3][3] = tr[4][4] = 0;
        }
        else if(cur == 0) {
            tr[1][2] = 0;
            tr[1][1] = 1;
            tr[0][0] = tr[2][2] = tr[3][3] = tr[4][4] = 0;
        }
        else if(cur == 1) {
            tr[2][3] = 0;
            tr[2][2] = 1;
            tr[0][0] = tr[1][1] = tr[3][3] = tr[4][4] = 0;
        }
        else if(cur == 6) {
            tr[3][3] = 1;
            tr[4][4] = 1;
            tr[0][0] = tr[1][1] = tr[2][2] = 0;
        }
        else if(cur == 7) {
            tr[3][4] = 0;
            tr[3][3] = 1;
            tr[0][0] = tr[1][1] = tr[2][2] = tr[4][4] = 0;
        }
    }
};

Info operator + (const Info & a,const Info & b) {

    Info rt;
    memset(& rt,0x3f,sizeof(rt));
    for(int i = 0;i <= 4;i ++)
      for(int j = 0;j <= 4;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]);
    return rt;
}

struct node {

    Info info;
    node *ls,*rs;
}pool[4 * N],*tail = pool,*root;

node *build(int l,int r) {

    node *nd = ++ tail;
    if(l == r) {
        nd -> info.init(a[l]);
        return nd;
    }
    int mid = (l + r) >> 1;
    nd -> ls = build(l,mid);
    nd -> rs = build(mid + 1,r);
    nd -> info = nd -> ls -> info + nd -> rs -> info;
    return nd;
}

Info query(node *nd,int l,int r,int L,int R) {

    if(l >= L && r <= R) {
        return nd -> info;
    }
    int mid = (l + r) >> 1;
    if(R <= mid) return query(nd -> ls,l,mid,L,R);
    else if(L > mid) return query(nd -> rs,mid + 1,r,L,R);
    else return query(nd -> ls,l,mid,L,R) + query(nd -> rs,mid + 1,r,L,R);
}

int main( ) {

    freopen("year.in","r",stdin);
    freopen("year.out","w",stdout);
    scanf("%s",s + 1);
    int len = strlen(s + 1);
    for(int i = 1;i <= len;i ++)
      a[i] = s[i] - ‘0‘;
    root = build(1,len);
    scanf("%d",& q);
    while(q --) {
        int l,r;
        scanf("%d%d",& l,& r);
        Info nd = query(root,1,len,l,r);
        if(nd.tr[0][4] == 1061109567) printf("-1\n");
        else printf("%d\n",nd.tr[0][4]);
    }
}

原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9538923.html

时间: 2024-10-30 05:19:37

18.8.26 考试总结的相关文章

9.26 考试

好久没有写博客了... 言归正传奥 T1就是个送分题... #include <cstdio> #include <cstring> #include <iostream> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; int n,maxp; ll a[26],b[26],c[26],d[26]; ll ans; int main(){ freopen(&

18.2.26 codevs3143 二叉树的序遍历

题目描述 Description 求一棵二叉树的前序遍历,中序遍历和后序遍历 输入描述 Input Description 第一行一个整数n,表示这棵树的节点个数. 接下来n行每行2个整数L和R.第i行的两个整数Li和Ri代表编号为i的节点的左儿子编号和右儿子编号. 输出描述 Output Description 输出一共三行,分别为前序遍历,中序遍历和后序遍历.编号之间用空格隔开. 样例输入 Sample Input 5 2 3 4 5 0 0 0 0 0 0 样例输出 Sample Outp

18.04.26 魔兽世界终极版

A:魔兽世界终极版 描述 魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部.两个司令部之间是依次排列的若干城市,城市从西向东依次编号为1,2,3 .... N ( N <= 20 ).红魔军的司令部算作编号为0的城市,蓝魔军的司令部算作编号为N+1的城市.司令部有生命元,用于制造武士. 两军的司令部都会制造武士.武士一共有 dragon .ninja.iceman.lion.wolf 五种.每种武士都有编号.生命值.攻击力这三种属性. 双方的武士编号都是从1开始计算.红方制造出来的第 n 个

18.06.26 16年程设期末10:游览规划

描述 一年一度的暴雪嘉年华(BlizzCon’16)即将盛大开幕,作为贪玩的助教小J,自然翘掉了程设期末前往参加.本届嘉年华为期m天,在这24*m小时的时间里,观众买券入场后方可体验各种免费及付费的游戏项目.参加本届嘉年华,首先需要在现场购买入场券,现场可以购买的入场券有三种,允许叠加购买使用: 单日券:售价100美金,购买后可以进入会场游玩24小时: 双日券:售价150美金,购买后可以进入会场游玩48小时: 三日券:售价200美金,购买后可以进入会场游玩72小时. 买券进入会场后,就可以在规定

5.26 考试修改+总结

论写5K+的代码在只有样例的条件下都可以调对 由此可见,勇气才是成功的关键 先放题解吧 第一题上午写的暴力不小心忘记题目换根之后还会染色了 然后就挂成了5分QAQ 有很大的部分分是SDOI染色,还有一部分是旅行 但是考试犯懒没有写 很容易发现任何一种颜色在树上都是连续的一段 那么我们不妨这么定义,如果一条边两端颜色不相同,我们定义为虚边,会对子树每个答案产生+1的贡献 如果两端颜色相同,我们定义为实边,不会产生贡献 不难发现,这样定义后的实边和虚边的性质和LCT的定义是一样的 我们考虑使用LCT

18.1.1考试

今天考的题目都是DP,本来以为会有什么图论...根据今天题目比较水的原因,我直接放解题报告,大家应该可以看得懂.. T1 Source #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> using namespace std; const int maxn=10000+10,maxm=10010; #define file(a) freopen(a".i

18.2.26深信服Web实习生补坑(已拿到offer)----持续更新中,还没写完

26号晚上8点左右收到电话,面试大概一小时左右,发挥的一般,问到的大部分都答出来了,有些没有讲好.然后面试官说等通知,问了评价,面试官说我现在大三懂这么多已经很不错了,表达能力需要加强,有点紧张口吃.30分钟后收到实习生offer邮件.这里只记录下几个答的不好的点. 1.var和不var的区别? 先问了作用域相关,然后问如果不用var声明一个变量是属于什么变量,这个是全局变量,肯定一下子答上来,然后又问那么不var的和用var声明的变量有什么区别? js里面的属性是有权限设置的,比如我们直接创建

18.8.13 考试总结

1.1 问题描述请构造一颗n 个节点的树,使得其价值最大.f(d) 表示树上,度数为d 的一个点能够获取的价值.这棵树的价值为Σni=1 f(di)di 表示第i 个点的度数1.2 输入第一行一个整数T,接下来T 组数据,每组数据输入两行.第一行输入整数n.第二行输入n ?? 1 个整数f(i) 代表f(1) f(n ?? 1).1.3 输出对于每组数据输出一行,为能够构造的树的最大价值. 一开始我以为是一道树形dp... 考完了才知道原来这个是一道背包问题 n个节点 总共有2n - 2个度数

18.9.7 考试总结

啊今天是生日之后的第三天呢 然后我就大凶了.. 略微难受 啊这道题正解是倒着搞得 ()然而蒟蒻我并不会... 于是就学习wans大佬的程序写的二分 + 正着搞得$Spfa$ $Spfa$最坏是 $nm$ 显然这道题是可以直接跑过的 所以对于起点二分一个最大货物量 然后Spfa跑每个点的最大值就可以了 按照题目意思来稿还是很清楚的 代码 #include <bits/stdc++.h> #define oo 10000000 using namespace std; const int N =