【ACM算法竞赛日常训练】DAY1题解与分析
DAY1 共四题:
- 月月查华华的手机:https://ac.nowcoder.com/acm/problem/23053
- Rinne Loves Edges:https://ac.nowcoder.com/acm/problem/22598
- 逆序对:https://ac.nowcoder.com/acm/problem/14731
- Xorto:https://ac.nowcoder.com/acm/problem/14247
视频教程:https://www.bilibili.com/video/BV1JX4y1d7LC
作者:Eriktse
简介:19岁,211计算机在读,现役ACM银牌选手力争以通俗易懂的方式讲解算法!️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)
个人博客:www.eriktse.com
月月查华华的手机
- tag:动态规划
注意:子序列是可以分隔开的,请区别子串和子序列。
我们定义dp[i][j]表示在母串中第i位右边最近的字符j的位置,如果不存在则为-1,初始值为-1。
倒序处理出dp数组后,对每一个子串进行判断。
判断的思路是:当前在母串的位置j,当前子串字符为k,那么我找dp[j][k]看看是否存在,如果有就让j跳过去,如果没有就说明母串中不存在这个子序列。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6 + 9;
char s[maxn];
int dp[maxn][30], now[30];//dp[i][j]表示母串中第i位右边最近的字符j的位置
signed main()
{
    memset(dp, -1, sizeof dp);
    memset(now, -1, sizeof now);
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    for(int i = n;i >= 0; -- i)
    {
        for(int j = 0;j < 26; ++ j)dp[i][j] = now[j];
        if(i > 0)now[s[i] - 'a'] = i;
    }
    int T;scanf("%lld", &T);
    while(T --)
    {
        scanf("%s", s + 1);
        int m = strlen(s + 1);
        bool ans = true;
        for(int i = 1, j = 0;i <= m; ++ i)
        {
            int k = s[i] - 'a';
            if(dp[j][k] == -1)
            {
                ans = false;
                break;
            }
            else j = dp[j][k];
        }
        printf("%s\n", ans ? "Yes" : "No");
    }
    return 0;
}
Rinne Loves Edges
- tag:简单图论,树
首先以s作为根构造一棵树,fa[x]表示x的父亲。
不难发现,假如我要使得点x为根的子树的所有叶子到不了s,那么可以通过删除x - fa[x]这条边或删除x与所有儿子节点的边,那么对于x的儿子亦是如此。
所以我们就有了dp方程, w[x]为x与fa[x]的边权,dp[x]表示删除点x的最小代价(代码中的dp用dfs表示):
$$dp[x] = min(w[x], \sum_{y \in g[x] y \neq fa[x]}w[y])$$
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 9, inf = 1e18;
int w[maxn];//w[i]表示点i的父亲这条边的边权
vector<pair<int, int> > g[maxn];
int n, m, s;
int dfs(int x, int pre)//pre是x的父节点,返回删除节点x和父亲这条边的最小代价
{
    //有可能是根
    if(g[x].size() == 1 and x != s)return w[x];
    int res = 0;//res表示子节点的代价之和
    for(auto &i : g[x])
    {
        int y = i.first, dw = i.second;
        //x -> y, cost = dw
        if(y == pre)continue;//如果下一个点是当前的父节点,就不进入
        w[y] = dw;
        res += dfs(y, x);
    }
    return min(w[x], res);
}
signed main()
{
    scanf("%lld %lld %lld", &n, &m, &s);
    for(int i = 1;i <= m; ++ i)
    {
        int x, y, w;scanf("%lld %lld %lld", &x, &y, &w);
        g[x].push_back({y, w});
        g[y].push_back({x, w});
    }
    w[s] = inf;
    printf("%lld\n", dfs(s, 0));
    return 0;
}
逆序对
- tag:组合数学
我们知道只有(1, 0)这样的二元组会对答案产生贡献,那么我们枚举第二位,然后找左边有多少个1即可。
对于第i位,左边有$2^{i - 1}$种情况,每种情况平均都是$\frac{i-1}{2}$个1,然后右边有$2^{n - i}$种情况,会使得区间[0, i]的情况重复多次。
所以第i位的贡献$a_i = 2^{n-1} \times \frac{i-1}{2} = 2 ^ {n-2} \times (i - 1) $。
答案是:
$$ ans=\sum_{i=1}{n}a_i=2\sum_{i=1}{n}(i-1)=2\times n\times (n-1) $$
#include "bits/stdc++.h"
#define int long long
const int mod = 1e9 + 7;
int ksm(int a, int b) {
	int res = 1;
	while (b > 0) {
		if (b & 1) res = res * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return res;
}
int mo(int x){return (x % mod + mod) % mod;}
signed main() {
	int n; std::cin >> n;
	if (n == 1) {
		std::cout << 0 << "\n";
	} else if (n == 2) {
		std::cout << 1 << "\n";
	} else {
        int m = n % mod;
		std::cout << mo(m * m % mod - m) * ksm(2, n - 3) % mod;
	}
    return 0;
}
Xorto
- tag: map, vector, 异或xor
将所有的异或和结果存到一个map里,每一个异或和结果对应一个vector,里面存下了所有的异或和相同的区间,且按照左端点为第一关键字,右端点为第二关键字的顺序排列好。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 9;
int a[maxn];
unordered_map<int, vector<pair<int, int>> > mp;
signed main()
{
    int n;scanf("%lld", &n);
    for(int i = 1;i <= n; ++ i)scanf("%lld", a + i);
    for(int i = 1;i <= n; ++ i)
    {
        int xorsum = 0;
        for(int j = i;j <= n; ++ j)
        {
            xorsum ^= a[j];
            if(!mp.count(a[j]))mp[a[j]] = vector<pair<int, int> >();
            mp[xorsum].push_back({i, j});
        }
    }
    int ans = 0;
    for(auto &it : mp)
    {
        vector<pair<int, int> >& v = it.second;
        //v中的所有区间,异或和都相同
        for(int i = 0;i < v.size(); ++ i)
        {
            int j = upper_bound(v.begin(), v.end(), v[i].second,
                                [](const int &x, const pair<int, int>& p)
                                {
                                    return x < p.first;
                                }) - v.begin();
            ans += v.size() - j;
        }
    }
    printf("%lld\n", ans);
    return 0;
}
本文由eriktse原创,创作不易,如果对您有帮助,欢迎小伙伴们点赞、收藏、留言
【ACM算法竞赛日常训练】DAY1题解与分析的更多相关文章
- 【经验总结】Java在ACM算法竞赛编程中易错点
		一.Java之ACM易错点 1. 类名称必须采用public class Main方式命名 2. 在有些OJ系统上,即便是输出的末尾多了一个“ ”,程序可能会输出错误,所以在我看来好多OJ系统做的是非 ... 
- ACM算法竞赛:抄课文
		题目如下: 比如现在要写一句话 Hello world 输入: n (n > 0) 比如输入的n为10,就将Hello world打印十 #include <stdio.h> #in ... 
- 华南师大 2017 年 ACM 程序设计竞赛新生初赛题解
		题解 被你们虐了千百遍的题目和 OJ 也很累的,也想要休息,所以你们别想了,行行好放过它们,我们来看题解吧... A. 诡异的计数法 Description cgy 太喜欢质数了以至于他计数也需要用质 ... 
- 算法竞赛入门经典训练指南——UVA 11300  preading the Wealth
		A Communist regime is trying to redistribute wealth in a village. They have have decided to sit ever ... 
- 算法竞赛入门经典——读书笔记day1
		1-1:整数值用%d输出,实数用%f输出. 1-2:整数/整数=整数,浮点数/浮点数=浮点数. 1-3:scanf中的占位符和变量的数据类型应一一对应,且每个变量前需要加&符号. 1-4:在算 ... 
- (Step1-500题)UVaOJ+算法竞赛入门经典+挑战编程+USACO
		http://www.cnblogs.com/sxiszero/p/3618737.html 下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年 ... 
- THUSC2017 Day1题解
		THUSC2017 Day1题解 巧克力 题目描述 "人生就像一盒巧克力,你永远不知道吃到的下一块是什么味道." 明明收到了一大块巧克力,里面有若干小块,排成n行m列.每一小块都有 ... 
- 算法竞赛入门经典+挑战编程+USACO
		下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发. 一.UVaOJ http://uva.onlinej ... 
- 2015浙江财经大学ACM有奖周赛(一) 题解报告
		2015浙江财经大学ACM有奖周赛(一) 题解报告 命题:丽丽&&黑鸡 这是命题者原话. 题目涉及的知识面比较广泛,有深度优先搜索.广度优先搜索.数学题.几何题.贪心算法.枚举.二进制 ... 
- Aho-Corasick automaton(AC自动机)解析及其在算法竞赛中的典型应用举例
		摘要: 本文主要讲述了AC自动机的基本思想和实现原理,如何构造AC自动机,着重讲解AC自动机在算法竞赛中的一些典型应用. 什么是AC自动机? 如何构造一个AC自动机? AC自动机在算法竞赛中的典型应用 ... 
随机推荐
- 20192305 王梓全Python程序设计实验一报告
			20192305 王梓全Python程序设计实验一报告 课程:<Python程序设计> 班级: 1923 姓名: 王梓全 学号:20192305 实验教师:王志强 实验日期:2021年4月 ... 
- oracle 实例无法启动和初始化
			1 先看oracle的监听和oracle的服务是否都启动了.启动oracle监听:cmd的命令行窗口下,输入lsnrctl start,回车即启动监听.2 查看oracle的sid叫什么,比如创建数据 ... 
- 当你的数据集是hdf5格式的文件时,肿么办?
			最近,自己构建了一个卷积神经网络,从网上下载到的数据集是hdf5格式的,希望用这个数据集来训练一下自己构建的这个神经网络. 1. 什么是hdf5? HDF5是二进制数据格式,用于在磁盘上存储巨大的数值 ... 
- “jupyter notebook 不能导入python库但是终端上可以实现”的问题的解决
			在使用jupyter notebook的过程中,创建了一个新的环境(anaconda中env)后遇到了这样一个问题,就是: 在jupyter notebook上运行程序,中间发现有一个python库未 ... 
- 类和动态内存分配的课后习题(C++ prime plus)
			第一题 1. 对于下面的类声明: class Cow { char name[20]; char *hobby; double weight; public: Cow(); Cow(const cha ... 
- vue组件传参,父子组件以及兄弟组件(非常详细)
			一,父子组件传参. 1.首先在项目目录中新建template文件夹,里边包含父组件:List.vue以及子组件:firstComponent.vue,secondComponent.vue. 2.父组 ... 
- 枚举类list序列化与反序列化
			//序列化 public class AuthTypeEnumListJsonSerializer extends JsonSerializer<List> { @Override pub ... 
- 请求GET和POST的区别
			实际上GET和POST他们只有语义上的区别,之所以有我们所谓的区别是由于前端与后端达成的协议. 区别1:get请求不会附带请求体,而post请求有请求体. 区别2: get请求传递的信息量是有限的,适 ... 
- Mysql 的用户权限等操作管理与设置(创建、授权、修改、查看)
			注:请在 MySql 的客户端操作 1.创建用户 CREATE USER 'username'@'host' IDENTIFIED BY 'password';//例 CREATE USER 'use ... 
- centos7离线安装软件和软件包组
			需求: 在一个只有内网的服务器中安装某些需要进行源码编译的软件,并且该软件具有大量的依赖,最坑的是服务器只安装了基本的软件,现在需要手动将Development Tools软件包组安装到该服务器,然后 ... 
