当前位置: 首页 > ai >正文

洛谷P12238 [蓝桥杯 2023 国 Java A] 单词分类

[Problem Discription] \color{blue}{\texttt{[Problem Discription]}} [Problem Discription]

在这里插入图片描述
Copy from luogu.

[Analysis] \color{blue}{\texttt{[Analysis]}} [Analysis]

既然都是字符串前缀的问题了,那当然首先就应该想到 Trie \text{Trie} Trie 树。

我们可以发现这么一个性质,如果选从根到 Trie \text{Trie} Trie 树上某一点形成给定字符串作为前缀,那么子树内所有的字符串都会被归为这个类,子树外的其它字符串都不会被归为这个类。

于是可以想到在 Trie \text{Trie} Trie 上进行 dp \text{dp} dp。用 f u , k f_{u,k} fu,k 表示把子树 u u u 内的字符串分为 k k k 类的方案数。

根据上面的性质,其实这个 dp \text{dp} dp 等价于从 u u u 及其子树中选出 k k k 个点的方案数,因而转移方程显然。

但是需要注意的是,如果选择了 u u u 这个点,那么 u u u 的子树的点都不可以被选取,不然就会有些字符串被分入两个组中。当然,如果 k = 1 k=1 k=1,那么选择 u u u 也是可能的合法的选择。

另外,因为每个字符串都要被分入其中一个组,因此 k k k 不能小于等于 0 0 0

考虑清楚边界情况就可以开始写代码了。

另外,由于每个节点最多也就 3 3 3 个子树,因此没必要写得那么复杂,枚举每棵子树内选取多少个点就可以了。

时间复杂度最多 O ( N K × max ⁡ { ∣ s ∣ } ) O(NK \times \max \{ |s| \}) O(NK×max{s})。其中 max ⁡ { ∣ s ∣ } \max \{ |s| \} max{s} 表示字符串长度的最大值。

Code \color{blue}{\text{Code}} Code

const int mod=1e9+7;
const int N=210,M=110,L=2010;int id(char ch){switch (ch){case 'l': return 0;case 'q': return 1;case 'b': return 2;default: return -1;}
}struct Trie_Tree{int ch[L][3],ndcnt,cnt[L],child[L];bool flag[L];void init(){memset(ch,-1,sizeof(ch));memset(cnt,0,sizeof(cnt));memset(flag,false,sizeof(flag)); memset(child,0,sizeof(child));ndcnt=0;}void insert(string s){int l=s.length(),u=0;for(int i=0;i<l;i++){int c=id(s[i]);if (ch[u][c]==-1){ch[u][c]=++ndcnt;++child[u]; }++cnt[u];//统计字符串的数量 u=ch[u][c];}++cnt[u];flag[u]=true;}
}trie;int f[L][M],n,m;int dp(int u,int k){ if (trie.cnt[u]<k) return 0;if (~f[u][k]) return f[u][k];if (k<=0) return 0; if (trie.flag[u]) return k==1;int res=((k==1)?1:0);if (trie.child[u]==1){int c;if (~trie.ch[u][0]) c=trie.ch[u][0];else if (~trie.ch[u][1]) c=trie.ch[u][1];else c=trie.ch[u][2];res=(res+dp(c,k))%mod;}else if (trie.child[u]==2){int c1,c2;if (~trie.ch[u][0]){c1=trie.ch[u][0];if (~trie.ch[u][1]) c2=trie.ch[u][1];else c2=trie.ch[u][2];}else c1=trie.ch[u][1],c2=trie.ch[u][2];for(int i=1;i<k;i++)res=(res+1ll*dp(c1,i)*dp(c2,k-i)%mod)%mod;}else{for(int i=1;i<k;i++)for(int j=1;j<k-i;j++)res=(res+1ll*dp(trie.ch[u][0],i)*dp(trie.ch[u][1],j)%mod*dp(trie.ch[u][2],k-i-j)%mod)%mod;}return f[u][k]=res;
}int main(){cin>>n>>m;trie.init();for(int i=1;i<=n;i++){string s;cin>>s;trie.insert(s);}memset(f,-1,sizeof(f));printf("%d",dp(0,m));return 0;
}
http://www.xdnf.cn/news/2775.html

相关文章:

  • 从车道检测项目入门open cv
  • 【图片识别成表格】批量图片识别成excel表格,批量识别图片区域文字保存到excel表格,基于WPF和腾讯OCR的识别方案
  • MyBatis 使用 POJO 参数动态查询教程
  • leetcode继续c++10/100
  • UDP数据报和TCP流套接字编程
  • BUUCTF——Online Tool
  • 日本IT行业|salesforce开发语言占据的地位
  • Java后端开发day39--方法引用
  • 如何系统学习音视频
  • gitmodule怎么维护
  • 千问3(Qwen3)模型开源以及初体验
  • 设计模式(工厂模式)
  • Android Studio Profiler
  • 矩阵区域和 --- 前缀和
  • 【计算机视觉】目标检测:深度解析YOLOv5:下一代实时目标检测框架实战指南
  • 《图像采集与处理技术的研究与洞察》
  • 从架构原理到落地实践:Apache SeaTunnel×Cloudberry数据集成全解读
  • SQL命令一:SQL 基础操作与建表约束
  • 解决 Flutter 在 iOS 真机上构建失败的问题
  • 使用Qt QAxObject解决Visual Fox Pro数据库乱码问题
  • Token-Budget-Aware LLM Reasoning
  • c网络库libevent的http常用函数的使用(附带源码)
  • 玩玩OCR
  • RPC复习
  • 【MCP Node.js SDK 全栈进阶指南】高级篇(5):MCP之微服务架构
  • 对话式 BI:让数据洞察从“专业门槛”变为“对话本能”
  • 多模态知识图谱与大模型 图解合集(干中学ing)
  • 【机器学习】​碳化硅器件剩余使用寿命稀疏数据深度学习预测
  • matplotlib
  • 阿里云服务器(ECS)基础指南:从入门到核心场景解析​