P1666前缀单词
题目传送门点我传送
Ⅰ.字典树+树型DP
非常奇妙的一种解法
第一部分:构建树
先对来的单词读入,插入字典树
然后对于一颗字典树,其实是有很多无用边的,所以我们需要删去一些边
删去非单词节点和非单词节点之间的边,其实就是下面这个函数
void rebuild(int now,int fa)
{
if(isok[now])//当前节点是单词
{
vec[fa].push_back(now);//连边
fa=now;//换爸爸了
}
for(int i=1;i<=26;i++)
{
if(!tree[now][i]) continue;
rebuild(tree[now][i],fa);//递归
}
}
第二部分:树型DP
对于每一棵子树而言,右选和不选两种方案
选,则子树上的节点都不能再选,即为
\(dp[i][1]=1\)
不选,则子树上的节点可选可不选
\(f[i][0] = \prod_{j\in son[i]}(f[j][0]+f[j][1])\)
因为是计算方案,决策之间是彼此联系的,所以是相乘
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5009;
int n;
int tree[maxn][27];int isok[maxn],tot;
void insert(string s)
{
int now=0;
for(int i=0;i<s.length();i++)
{
int k=s[i]-'a'+1;
if(!tree[now][k])
tree[now][k]=++tot;//没有节点,新创建一个节点
now=tree[now][k];//去下一个节点
}
isok[now]=1;//标记单词
}
vector<int>vec[maxn];
void rebuild(int now,int fa)
{
if(isok[now])//当前节点是单词
{
vec[fa].push_back(now);//连边
fa=now;//换爸爸了
}
for(int i=1;i<=26;i++)
{
if(!tree[now][i]) continue;
rebuild(tree[now][i],fa);//递归
}
}
ll dp[maxn][3];
void ddp(int now)//开始DP
{
dp[now][1]=dp[now][0]=1;
for(int i=0;i<vec[now].size();i++)//遍历所有儿子
{
int v=vec[now][i];
ddp(v);
dp[now][0]=dp[now][0]*(dp[v][0]+dp[v][1]);//不选父节点
}
}
int main()
{
cin>>n;
string s;
for(int i=1;i<=n;i++) cin>>s,insert(s);
for(int i=1;i<=26;i++)
{
if(!tree[0][i]) continue;
rebuild(tree[0][i],0);//有结点才向下建树
}
ddp(0);//树型DP
cout<<dp[0][0];
}
Ⅱ.线性DP
我们预处理一个\(f[i][j]\)表示第i个单词与第j个单词是否能共存,
然后考虑一个\(dp[i]\)表示在前i个单词中,必须包含第i个单词的子集个数,首先\(dp[i]=1\)(只包含自己一个元素的一个子集方案数)
那么如果前面存在一个\(j<i\),并且\(f[i][j]=1\)(即i与j可以共存),那么j所有的子集方案数加上一个i元素就形成了对应新的方案,那么状态就由j转移到i了,最后,直接累计\(dp[1....n]\)即可,当然最后还要算上空集哟。
但是,这么做的前提是单词必须先排序
为什么呢??因为在\(dp[j]\)的方案中,可能有是\(a[i]\)前缀的单词,那我们就不能转移
但如果按照字典序排过之后,就不存在这种问题。
#include <bits/stdc++.h>
using namespace std;//dp[i]为必须包括i的个数
typedef long long ll;
ll vis[59][59],dp[59];
string a[59];
bool pan(int l,int r)
{
int p1=0,p2=0;
while(p1<a[l].length()&&p2<a[r].length())
if(a[l][p1++]!=a[r][p2++]) return false;
return true;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i],dp[i]=1;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(pan(i,j))
vis[i][j]=1;
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<i;j++)
{
if(vis[i][j]==0)//可以放一起
dp[i]+=dp[j];
}
}
ll ans=0;
for(int i=1;i<=n;i++) ans+=dp[i];
cout<<ans+1;
}
P1666前缀单词的更多相关文章
- P1666 前缀单词
P1666 前缀单词 tire树上跑dp 首先将trie树建出来,然后对于每个节点.考虑他的子节点. 子节点的方案数都互不干扰,所以子节点与其他子节点的的方案数可以利用乘法原理算出来. 然后如果这个节 ...
- 洛谷 P1666 前缀单词 题解
题意:给n个单词,如果单词a为单词b的前缀则a,b不能共存,问能共存的集合数(包括空集) 一道dp题,排序后判断,f[i][j]表示i和j是否能共存,f[i][j]=1表示能共存,初始化dp[i]=1 ...
- 【luogu P1666 前缀单词】 题解
题目链接:https://www.luogu.org/problemnew/show/P1666 10.13考试题 当时没想出来,觉得是要用trie做,在trie上跑一个树形dp 结果是写了个子集枚举 ...
- Luogu P1666 前缀单词
校内资格赛题目,差点高一就要\(\tt{AFO}\)了 30分思路 对30%的数据,满足$1≤n≤10 $ 所以我们可以子集枚举,实际得分40pts #include<iostream> ...
- 【洛谷 P1666】 前缀单词 (Trie)
题目链接 考试时暴搜50分...其实看到"单词","前缀"这种字眼时就要想到\(Trie\)的,哎,我太蒻了. 以一个虚点为根,建一棵\(Trie\),然后\( ...
- [luoguP1666] 前缀单词(DP)
传送门 先把所有字符串按照字典序排序一下 会发现有字符串x和y(x再y前面,即字典序小),如果x不是y的前缀,那么在x前面不是x前缀的字符串也不是y的前缀 这样就可以DP了 f[i][j]表示前i个字 ...
- [LeetCode] Word Squares 单词平方
Given a set of words (without duplicates), find all word squares you can build from them. A sequence ...
- HDU 1251 字典树(前缀树)
题目大意 :Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).(单词互不相同) ...
- 如何区别英语前缀pri,pro,per,pre?
pri- 前缀pri-来源于拉丁语的这几个形容词“prim.us”, “prim.a”, “prim.um”,表示“第一的”的意思,和“pri.or”, “pri.or”, “pri.us”,是“优先 ...
随机推荐
- shell命令-if语句
判断参数的个数 -ne 不等于 -eq 等于 -gt 大于 -lt 小于 -ge 大于等于 -le 小于等于 if [ "$#" -ne 1 ];then echo "n ...
- 带你五分钟了解python的函数式编程与闭包
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:梁唐 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行 ...
- 基础_TCP/IP
概念明确: 1:TCP/IP代表传输控制协议/网际协议,指的是一系列协议 为什么会叫TCP/IP.因为用的多, 2:HTTP 是属于应用层的协议 3:OSI七层模型和TCP/IP 平等,只是TCP/ ...
- 通达OA任意用户登录 漏洞复现
0x00 漏洞简介 通达OA国内常用的办公系统,使用群体,大小公司都可以,其此次安全更新修复的高危漏洞为任意用户登录漏洞.攻击者在远程且未经授权的情况下,通过利用此漏洞,可以直接以任意用户身份登录到系 ...
- selenium 时间等待的方法
一.强制等待固定秒数 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } 执行到sl ...
- 漫谈LiteOS-端云互通组件-MQTT开发指南(上)
1.介绍 SDK简介 Agent Tiny是部署在具备广域网能力.对功耗/存储/计算资源有苛刻限制的终端设备上的轻量级互联互通中间件,您只需调用API接口,便可实现设备快速接入到物联网平台以及数据上报 ...
- 设计模式-原型模式(Prototype)【重点:浅复制与深复制】
讲故事 最近重温了一下星爷的<唐伯虎点秋香>,依然让我捧腹不已,幻想着要是我也能有一名秋香如此的侍女,夫复何求呀,带着这个美好的幻想沉沉睡去... 突然想到,我是一名程序猿呀,想要什么对象 ...
- 为什么redis是单线程的以及为什么这么快?
官网的说法 我们先来认真看一下官网的说法.翻译过来大意如下: CPU并不是您使用Redis的瓶颈,因为通常Redis要么受内存限制,要么受网络限制.例如,使用在一般Linux系统上运行的流水线Redi ...
- PHP Ajax 跨域问题解决方案
本文通过设置Access-Control-Allow-Origin来实现跨域. 例如:客户端的域名是client.0751.tv,而请求的域名是server.0751.tv. 如果直接使用ajax访问 ...
- php环境兼容性问题---压缩格式及其配置简介
php环境兼容性问题-- 内容编码错误 无法显示您尝试查看的页面,因为它使用了无效或者不支持的压缩格式. 请联系网站的所有者以告知此问题. 以前也遇到过同样的问题,记得是PHP代码ob_start(' ...