20171010离线赛总结

2023-10-26

题解:

第一题:字符连通块

  这道题还是比较好想的,首先把每个连通块标记出来,并用第一次扫到的点标记为这个连通块的父节点,接下来要做的就是把一个‘*’周围的连通块连通起来。不过要注意一点,在连通标记的时候不要用memset,memset的复杂度是m/8(m是数组大小),会很慢,直接循环标记就好了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 1050
#define FOR(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;++i)
#define DOR(i,a,b) for(int i=(a),i##_end_=(b);i>=i##_end_;--i)
using namespace std;
char pic[M][M];
int n,m;
char s[M];
bool mark[M][M];
int tmp;
int drx[]= {0,1,-1,0},dry[]= {1,0,0,-1};
struct node{
    int x,y;
}Fa[M][M];
int size[M][M];
void DFS(int x,int y,int fax,int fay){
    Fa[x][y].x=fax;
    Fa[x][y].y=fay;
    tmp++;
    mark[x][y]=true;
    FOR(i,0,3){
        int nx=x+drx[i],ny=y+dry[i];
        if(nx<=n&&nx>0&&ny<=m&&ny>0&&!mark[nx][ny]&&pic[nx][ny]=='.')
            DFS(nx,ny,fax,fay);
    }
}
bool Mark[M][M];
int create(int i,int j){
    int res=0;
    FOR(k,0,3){
        int nx=i+drx[k],ny=dry[k]+j;
        if(nx>0&&nx<=n&&ny>0&&ny<=m){
            if(!Mark[Fa[nx][ny].x][Fa[nx][ny].y]){
                Mark[Fa[nx][ny].x][Fa[nx][ny].y]=1;
                res+=size[Fa[nx][ny].x][Fa[nx][ny].y];
            }
        }
    }
    FOR(k,0,3){
        int nx=i+drx[k],ny=dry[k]+j;
        Mark[Fa[nx][ny].x][Fa[nx][ny].y]=0;
    }
    return res+1;
}
struct AC{
    void solve(){
        FOR(i,1,n){
            FOR(j,1,m)if(pic[i][j]=='.'&&!mark[i][j]){
                tmp=0;
                DFS(i,j,i,j);
                size[i][j]=tmp;
            }
        }
        int ans=0;
        FOR(i,1,n){
            FOR(j,1,m)if(pic[i][j]=='*'){
                if(create(i,j)>ans)ans=create(i,j);
            }
        }
        cout<<ans<<endl;
    }
}AK;
int main() {
    cin>>n>>m;
    FOR(i,1,n) {
        scanf("%s",s+1);
        FOR(j,1,m)pic[i][j]=s[j];
    }
    AK.solve();
    return 0;
}

第二题:回文子序列

  这道题比较玄学,我用的是区间dp来写的,但是其他人收到完美队形的启发,秒A,我辛辛苦苦写了半天,什么数据都对上了(包括给的大数据),但就是错了。浑身难受。
  这道题可以这么认为,有一个区间有两种情况,要么是首尾相同,要么首尾不同,首尾不同的情况,可以用容斥原理解释,dp[i][j]=dp[i][j-1]+dp[i+1][j-1]-dp[i+1][j-1]。首尾相同的话,就可以把之前的所有情况都给转移过来了,即dp[i][j]=dp[i+1][j]+dp[i][j-1]+1,还要加上只有这两个点的情况。
  

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 2050
#define FOR(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;++i)
#define DOR(i,a,b) for(int i=(a),i##_end_=(b);i>=i##_end_;--i)
using namespace std;
const int P=100007;
int dp[M];//dp[i]
int n;
int flag[M][M];//flag[L][R]
char A[M];
char B[M];
void Add(int &x,int y) {
    x+=y;
    if(x>=P)x%=P;
}
void create() {
    FOR(i,1,n)flag[i][i]=1;
    FOR(j,1,n)DOR(i,j-1,1) {
        if(A[i]==A[j])Add(flag[i][j],flag[i+1][j]+flag[i][j-1]+1);
        else Add(flag[i][j],flag[i+1][j]+flag[i][j-1]-flag[i+1][j-1]+P);
    }
}
int main() {
    scanf("%s",A+1);
    n=strlen(A+1);
    create();
    cout<<flag[1][n]<<endl;
    return 0;
}

第三题:删边最小生成树

  这道题我打了个暴力就不打了,去写第二题了,其实不难看出,这道题只要在最小生成树上操作就可以了。若在最小生成树上的边被删去了,那么非树边就会与原来的树形成一个环,只要删除这个环中最小的边就可以了,如果这条边不在最小生成树上,就从这两个点不断往上走,更新每条树边被删去后的最小边。还是比较简单的,毕竟都是随机生成树,还有并查集压边的方法,请见YZK大佬的题解

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define M 200050
#define N 50050
#define INF 1000000009
#define FOR(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;++i)
#define DOR(i,a,b) for(int i=(a),i##_end_=(b);i>=i##_end_;--i)
using namespace std;
struct node {
    int fr,to,co,id;
    bool operator<(const node&a)const {
        return co<a.co;
    }
} A[M<<1],B[M];
int Fa[N];
void checkmin(int &x,int y){x=x<y?x:y;}
void checkmax(int &x,int y){x=x>y?x:y;}
bool mark[M<<1];
int degree[N];
int Min;
int n,m;
int ans[M];
int fa[M][2],dep[N];
void Init_ans(){
    FOR(i,1,m)ans[i]=INF;
}
void Init() {
    FOR(i,1,n)Fa[i]=i;
}
int Find(int x) {
    return x==Fa[x]?x:Fa[x]=Find(Fa[x]);
}
bool same(int x,int y) {
    return Find(x)==Find(y);
}
void unite(int x,int y) {
    Fa[Find(x)]=Find(y);
}
struct Node{
    int to,id,co;
};
vector<Node>edge[N];
Node makenode(int to,int id,int co){
    Node tmp;
    tmp.id=id;
    tmp.to=to;
    tmp.co=co;
    return tmp;
}
void dfs(int x,int f){
    dep[x]=dep[f]+1;
    fa[x][0]=f;
    FOR(i,0,edge[x].size()-1){
        int y=edge[x][i].to;
        if(y==f)continue;
        dfs(y,x);
        fa[y][1]=edge[x][i].id;
    }
}
int Kruskal(int x) {
    int res=0;
    Init();
    FOR(i,1,m) {
        node e=A[i];
        if(mark[e.id])continue;
        if(!same(e.fr,e.to)) {
            unite(e.fr,e.to);
            mark[e.id]=true;
            edge[e.fr].push_back(makenode(e.to,e.id,e.co));
            edge[e.to].push_back(makenode(e.fr,e.id,e.co));
            res+=e.co;
        }
    }
    return res;
}
int circle[M];
void up(int x,int y,int co){
    if(dep[x]>dep[y])swap(x,y);
    while(dep[y]!=dep[x]){
        checkmin(circle[fa[y][1]],co);
        y=fa[y][0];
    }
    while(x!=y){
        checkmin(circle[fa[y][1]],co);
        checkmin(circle[fa[x][1]],co);
        x=fa[x][0],y=fa[y][0];
    }
}
int main() {
    cin>>n>>m;
    Init_ans();
    FOR(i,1,m)scanf("%d%d%d",&A[i].fr,&A[i].to,&A[i].co),A[i].id=i;
    sort(A+1,A+m+1);
    fill(circle+1,circle+m+1,INF);
    int _=1;
    int Min=Kruskal(_);
    dfs(1,0);
    FOR(i,1,m)if(!mark[A[i].id])up(A[i].fr,A[i].to,A[i].co);
    FOR(i,1,m){
        if(!mark[A[i].id])ans[A[i].id]=Min;
        else {
            if(circle[A[i].id]==INF)ans[A[i].id]=-1;
            ans[A[i].id]=Min-A[i].co+circle[A[i].id];
        }
    }
    FOR(i,1,m){
        if(ans[i]>=INF)puts("-1");
        else printf("%d\n",ans[i]);
    }
    return 0;
}

总结:

  这次考得很一般,虽然保底分都拿过来了,但是时间分配出了点问题,第一题卡的时间也太长了,不能完全以水分为目的,而且第一个代码可能什么分都水不到。导致分配给第二题和第三题的时间很少,下次都要注意。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

20171010离线赛总结 的相关文章

  • LeetCode64. 最小路径和

    题目大意 求出从网络左上角到右下角的一条代价最小的路径和 题目分析 使用动态规划 求出左上角到网络中每个点的代价最小路径和 假设当前要求的是point i j 点 那么它的值就应该是从左上角到它上面那个点point i 1 j 的路径和 与
  • [HDU 5079][2014 Asia AnShan Regional Contest]Square(DP套DP)

    题目链接 http acm hdu edu cn showproblem php pid 5079 题目大意 给你一个 n n n 8 n middot n n le 8 的棋盘 上面有一些格子必须是黑色 其它可以染黑或者染白 对于一个棋盘
  • Summer Holiday HDU - 1827 强连通分量+缩点

    To see a World in a Grain of Sand And a Heaven in a Wild Flower Hold Infinity in the palm of your hand And Eternity in a
  • 蓝桥杯 题库 简单 每日十题 day2

    01 卡片 题目描述 本题为填空题 只需要算出结果后 在代码中使用输出语句将所填结果输出即可 小蓝有很多数字卡片 每张卡片上都是数字 0 到 9 小蓝准备用这些卡片来拼一些数 他想从 1 开始拼出正整数 每拼一个 就保存起来 卡片就不能用来
  • 备战2023蓝桥国赛-传纸条

    题目描述 解析 这道题想了我好久 一开始我是想假如只走一条路线 从 1 1 走到 m n 这种问题该怎么解决呢 针对这种问题我是设了dp k i j 表示走了k步到达 i j 的好心程度之和的最大值 然后根据这个来写出转移方程来计算 后面就
  • 最近在学动态规划,很有意思的算法(1)拿金币

    问题描述 有一个N x N的方格 每一个格子都有一些金币 只要站在格子里就能拿到里面的金币 你站在最左上角的格子里 每次可以从一个格子走到它右边或下边的格子里 请问如何走才能拿到最多的金币 输入格式 第一行输入一个正整数n 以下n行描述该方
  • POJ-1458最长公共子序列

    给定序列的子序列是给定序列 其中遗漏了一些元素 可能没有 给定序列X
  • 最短Hamilton路径

    题目 题目链接 题解 状压dp f i j 表示从0点按照路径i走到j点的最短距离 其中i为二进制数 1表示走过某点 0表示未走过某点 比如10010表示经过了1 4两个点 而不经过0 2 3点 状态转移为 假设沿路径i走到j点经过k点 且
  • 滑雪(记忆化搜索)

    题目 题解 记忆化搜索模板题 记忆化搜索的核心 本质是带剪枝的深搜 当某点的dp已赋值时 返回该值 其他情况进行深度搜索 模板 dfs u点 if u点的 dp 已经有值了 return u点的 dp 值 else 说明第一次到达u 则为u
  • 0动态规划中等 NC206 跳跃游戏(二)

    NC206 跳跃游戏 二 描述 给定一个非负整数数组nums 假定最开始处于下标为0的位置 数组里面的每个元素代表下一跳能够跳跃的最大长度 如果可以跳到数组最后一个位置 请你求出跳跃路径中所能获得的最多的积分 1 如果能够跳到数组最后一个位
  • C++---背包模型---装箱问题(每日一道算法2023.3.9)

    注意事项 本题是 动态规划 01背包 的扩展题 dp和优化思路不多赘述 题目 有一个箱子容量为 V 同时有 n 个物品 每个物品有一个体积 正整数 要求 n 个物品中 任取若干个装入箱内 使箱子的剩余空间为最小 输入格式 第一行是一个整数
  • 714阿里巴巴模拟面试

    介绍一下数据库分页 https www nowcoder com questionTerminal 3577280c810546658f06f19c01ff0345 给定一棵树 求出这棵树的直径 即两个节点距离的最大值 应该是左右子树遍历深
  • LeetCode338. 比特位计数

    题目连接 https leetcode cn com problems counting bits 解题思路 这道题需要计算从 0 到 num 的每个数的二进制表示中的 1 的数目 最直观的方法是对每个数直接计算二进制表示中的 1 的数目
  • 2023华为OD机试真题【最大平分数组/动态规划】

    题目描述 给定一个数组nums 可以将元素分为若干个组 使得每组和相等 求出满足条件的所有分组中 最大的平分组个数 输入描述 第一行输入 m 接着输入m个数 表示此数组 数据范围 1 lt M lt 50 1 lt nums i lt 50
  • 01背包(c++版)

    dp i j 表示从下标为 0 i 的物品里任意取 放进容量为j的背包 价值总和最大是多少 void test 2 wei bag problem1 vector
  • 【LeetCode75】第五十九题 第N个泰波那契数

    目录 题目 示例 分析 代码 题目 示例 分析 题目顾名思义 让我们求出第N个泰波那契数 也就是除了开头三个数之外 第四个数开始就是等于前三个数之和 不要和斐波那契数弄混了 斐波那契是前两个数的和 泰波那契是前三个数的和 也就是说当前数 我
  • Binary Tree on Plane【费用流】

    题目链接 CF 277 E 题意翻译 给你平面上 n 个点 2 n 400 要求用这些点组成一个二叉树 每个节点的儿子节点不超过两个 定义每条边的权值为两个点之间的欧几里得距离 求一个权值和最小的二叉树 并输出这个权值 其中 点 i 可以成
  • 讲解 最大流问题+最小花费问题+python(ortool库)实现

    文章目录 基本概念 图 邻接矩阵 最大流问题 python解决最大流问题 python解决最大流最小费用问题 喜欢的话请关注我们的微信公众号 你好世界炼丹师 公众号主要讲统计学 数据科学 机器学习 深度学习 以及一些参加Kaggle竞赛的经
  • C/C++---------------LeetCode第509. 斐波那契数

    斐波那契数列 题目及要求 暴力递归 备忘录的递归 动态规划 题目及要求 斐波那契数 通常用 F n 表示 形成的序列称为 斐波那契数列 该数列由 0 和 1 开始 后面的每一项数字都是前面两项数字的和 也就是 F 0 0 F 1 1 F n
  • 860.染色法判定二分图

    二分图是指一个图中的所有顶点可以分为两部分 并且每条边连接的是属于不同部分的两个顶点 include

随机推荐