说在前面

M↓写的第一篇题解,欢迎提出意见.

题目描述

瑞瑞有一堆的玩具木棍,每根木棍的两端分别被染上了某种颜色,现在他突然有了一个想法,想要把这些木棍连在一起拼成一条线,并且使得木棍与木棍相接触的两端颜色都是相同的,给出每根木棍两端的颜色,请问是否存在满足要求的排列方式。

例如,如果只有 \(2\) 根木棍,第一根两端的颜色分别为 red, blue,第二根两端的颜色分别为 red, yellow,那么 blue---red | red----yellow 便是一种满足要求的排列方式。

输入格式

输入有若干行,每行包括两个单词,表示一根木棍两端的颜色,单词由小写字母组成,且单词长度不会超过 \(10\) 个字母,最多有 \(250000\) 根木棍。

输出格式

如果木棒能够按要求排列,输出 Possible,否则输出 Impossible

输入输出样例

输入 #1

blue red
red violet
cyan blue
blue magenta
magenta cyan

输出 #1

Possible

分析

一根木棒就相当于一条边,木棒两边的颜色就是这条边所连的点,所以此题就是问一张图是否存在欧拉路。

欧拉路的判定很简单——所有点都连通(并查集),最多两个点的度为奇数(一个数组就可以搞定)。

那么这道题之所以是蓝题,是因为它对时间要求很严格——最多2.5e6个木棒,以及读入的字符串的处理。

字符串的处理

这里最最最快的方式是用\(trie\)。

\(trie\)中每个节点都有两个元素,\(num\)标记和\(26\)个指针,这里我们用数组模拟指针:

  1. 设\(0\)是根节点,实际上不代表任何的字母
  2. 对于要加入的每一个字符串,逐位考虑
  3. 如果当前节点没有str[i]这个子节点的话就新建一个节点为子节点
  4. 跳转到这个子节点,判断下一位
  5. 重复3、4步骤
  6. 如果最终的节点没有被分配一个编号的话,那么这个就新建一个编号给这个终节点

这样每一个字符串都有了唯一的编号,且编号是连续的,方便开数组等后续操作。

这就完成了trie的部分——字符串到正整数的映射。

struct Trie
{
int son[26],num;
}trie[2000010];
int n,trie_cnt;
int insert(string str)
{
int now=0;
for(int i=0;i<str.size();i++)
{
if(!trie[now].son[str[i]-'a']) trie[now].son[str[i]-'a']=++trie_cnt;
now=trie[now].son[str[i]-'a'];
}
if(!trie[now].num) trie[now].num=++n;
return trie[now].num;
}

可能有人会问为什么不用\(map\)?

因为\(map\)每次插入是\(logn\)的,而\(trie\)每次插入与字符串的长度有关(看作\(O(1)\)就好),题目也说了每个单词不超过\(10\)个字母。

当然也可以用\(unordered_map\)(需要C++11!),不会\(STL\)的同学可以用\(hash\)(这个还是有点慢)。

所以这里最优的就是\(trie\)啦!

判断欧拉路

欧拉路有个经典的故事——七桥问题,相信你应该耳熟能详了。

即:经过每条边正好一次,能不能把所有边都走一遍?

可以证明,只要整个图是连通的,且有奇数度的点不超过两个,那么就存在欧拉路!

  • 度的统计只需要在读入木棒的时候标记一下即可。

  • 判断连通图用并查集

读入

while(cin>>str)
{
x=insert(str);
cin>>str;
y=insert(str);
merge(x,y);
degree[x]++;
degree[y]++;
}

判断

判断这里我用了点小技巧,同时判断度和并查集。

  • 如果有相邻的两项的祖先是不同的,那么这肯定不是连通图,给flag加上一个大数字。
  • 如果这点的度是奇数,那么flag+1就好。
  • 最后判断flag,大于2说明奇度点多了或者图不连通,即不可能有欧拉路,反正则存在。
int flag=(degree[1]&1);
for(int i=2;i<=n;i++)
{
if(getf(i)!=getf(i-1)) flag+=10;
if(degree[i]&1) flag++;
}
if(flag>2) cout<<"Impossible"<<endl;
else cout<<"Possible"<<endl;

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#define re register
#define debug printf("Now is %d\n",__LINE__);
using namespace std; template<class T>inline void read(T&x)
{
char ch=getchar();
while(!isdigit(ch))ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
}
inline int read()
{
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x;
}
int G[55];
template<class T>inline void write(T x)
{
int g=0;
if(x<0) x=-x,putchar('-');
do{G[++g]=x%10;x/=10;}while(x);
for(re int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
} struct Trie
{
int son[26],num;
}trie[2000010];
int n,trie_cnt;
int insert(string str)
{
int now=0;
for(int i=0;i<str.size();i++)
{
if(!trie[now].son[str[i]-'a']) trie[now].son[str[i]-'a']=++trie_cnt;
now=trie[now].son[str[i]-'a'];
}
if(!trie[now].num) trie[now].num=++n;
return trie[now].num;
}
int f[500010];
int getf(int x)
{
while(x!=f[x]) x=f[x];
return x;
}
void merge(int x,int y)
{
x=getf(x);
y=getf(y);
f[x]=y;
}
int degree[500010];
int main()
{
string str;
int x,y;
for(int i=1;i<=500000;i++) f[i]=i;
while(cin>>str)
{
x=insert(str);
cin>>str;
y=insert(str);
merge(x,y);
degree[x]++;
degree[y]++;
}
int flag=(degree[1]&1);
for(int i=2;i<=n;i++)
{
if(getf(i)!=getf(i-1)) flag+=10;
if(degree[i]&1) flag++;
}
if(flag>2) cout<<"Impossible"<<endl;
else cout<<"Possible"<<endl;
return 0;
}

注意

在洛谷上提交的话,如果你\(#2\)无法通过,请注意数组大小问题:

最多有\(2.5e6\)根木棒,意味着最多有\(5e6\)种单词,所以数组要开到\(5e6\),而\(trie\)数组越大越好。

经过我的非精确计算,类似于线段树,每一层新建分支\(26\),最多\(10\)层,(最多\(141,167,095,653,376\)个叶子节点),而题目中有单词数量不超过\(2.5e6\),\(26^4=456976\),应该开到最多\(26+676+17576+2500000≈2,518,278\)即可。(这个是乱算的)

疑惑

如果出现,有两根相同的木棒怎么办?题目中并没有否认这种情况,但是不这样判断的话也过了啊……奇怪啊。

如果以后这道题修改或者加强了,请来踢我一脚(

洛谷P1333 瑞瑞的木棍 字符串 最短路的更多相关文章

  1. 洛谷P1333 瑞瑞的木棍(欧拉回路)

    题目描述 瑞瑞有一堆的玩具木棍,每根木棍的两端分别被染上了某种颜色,现在他突然有了一个想法,想要把这些木棍连在一起拼成一条线,并且使得木棍与木棍相接触的两端颜色都是相同的,给出每根木棍两端的颜色,请问 ...

  2. 洛谷 P4036 [JSOI2008]火星人(splay+字符串hash)

    题面 洛谷 题解 首先,我们知道求最长公共前缀可以用二分答案+hash来求 因为有修改操作, 考虑将整个字符串的hash值放入splay中 接着就是splay的基本操作了 Code #include& ...

  3. 洛谷 P3263 [JLOI2015]有意义的字符串

    洛谷 首先,看到\((\frac{(b+\sqrt{d})}{2})^n\),很快能够想到一元二次方程的解\(\frac{-b\pm\sqrt{\Delta}}{2a}\). 所以可以推出,\(\fr ...

  4. 洛谷 P1308 统计单词数【字符串+模拟】

    P1308 统计单词数 题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定 ...

  5. 洛谷P3234 抄卡组 [HNOI2014] 字符串hash

    正解:字符串hash 解题报告: 传送门! 字符串hash是字符串匹配中很常见的一个方法,原理也很好懂,这里就不做太多阐述辣有时间放到hash笔记里面去QAQ 题意不说了挺好理解的,自带一句话概括好评 ...

  6. 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]

    题目传送门 A Horrible Poem 题目描述 Bytie boy has to learn a fragment of a certain poem by heart. The poem, f ...

  7. 洛谷 P1308 统计单词数【字符串处理】

    题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给 ...

  8. 洛谷P1781 宇宙总统【排序+字符串】

    地球历公元6036年,全宇宙准备竞选一个最贤能的人当总统,共有n个非凡拔尖的人竞选总统,现在票数已经统计完毕,请你算出谁能够当上总统. 输入输出格式 输入格式: president.in 第一行为一个 ...

  9. 洛谷P1603——斯诺登的密码(字符串处理)

    https://www.luogu.org/problem/show?pid=1603#sub 题目描述 2013年X月X日,俄罗斯办理了斯诺登的护照,于是他混迹于一架开往委内瑞拉的飞机.但是,这件事 ...

  10. 洛谷P5292 [HNOI2019]校园旅行(二分图+最短路)

    题面 传送门 题解 如果暴力的话,我们可以把所有的二元组全都扔进一个队列里,然后每次往两边更新同色点,这样的话复杂度是\(O(m^2)\) 怎么优化呢? 对于一个同色联通块,如果它是一个二分图,我们只 ...

随机推荐

  1. VitePress全局组件封装

    前言 VuePress 主题默认有 <CodeGroup> 组件用于切换代码很方便. 如图所示: 痛点 使用 VitePress 后,官方没有提供 <CodeGroup> 组件 ...

  2. go context 子Goroutine超时控制

    context使用 Go语言第一形参通常都为context.Context类型,1. 传递上下文 2. 控制子Goroutine超时退出 3. 控制子Goroutine定时退出 package mai ...

  3. WebKit Inside: CSS 的匹配原理

    相关文章 WebKit Inside: CSS 样式表的解析 WebKit Inside: CSS 样式表的匹配时机 WebKit Inside: Acitvie 样式表 当WebView解析完所有外 ...

  4. MFC编程中与编码方式有关的宏定义的使用

    1 多字节字符集:char *strcpy(char *strDestination, const char *strSource); Unicode字符集:wchar_t *wcscpy(wchar ...

  5. Linux系统发邮件

    Linux系统发送邮件 管理服务器时我们经常需要写一些监测脚本,然后在出问题的时候通过邮件来通知 SMTP SMTP(Simple Mail Transfer Protocol)简易邮件传输通讯协议 ...

  6. 使用LLaMA-Factory训练LLM大模型并用ollama调用

    环境搭建 系统环境 需要Nvidia显卡,至少8G显存,且专用显存与共享显存之和大于20G 建议将非安装版的环境文件都放到非系统盘,方便重装或移植 以Windows11为例,非安装环境文件都放在 E ...

  7. CSS那些事读书笔记-2

    背景 作为一个后端开发,曾经尝试过学习前端,但是总觉不得要领,照猫画虎,而公司里又有专业的前端开发,工作中几乎接触不到实际的前端任务,所以前端的技能田野一直是一片荒芜.但是笔者深知前端的技能对找工作和 ...

  8. RegisterClass注册后getclass总是nil,why?

    这个问题有点老.但是有点烦人. 一般流程是 RegisterClass后通过getclass or findclass就会成功. 可是莫名其妙出现总是返回nil.咱也不清楚,网上找了好久,一个久远的帖 ...

  9. C#多线程编程(二)线程池与TPL

    一.直接使用线程的问题 每次都要创建Thread对象,并向操作系统申请创建一个线程,这是需要耗费CPU时间和内存资源的. 无法直接获取线程函数返回值 无法直接捕捉线程函数内发生的异常 使用线程池可以解 ...

  10. AIops

    How does AIOps work?With AIOps, your organization takes a more proactive approach to resolve IT oper ...