Codeforces 615C Running Track (Round #338 (Div. 2) C题) Trie + dp
2016-01-10 23:27
253 查看
题意
给你两个字符串t,s你的目标是使用尽量少的t拼出s
对于一个t,你可以做的是,只选取其中一个子串,正着或反着拼到s上
最后需要拼出完整的s
思路
首先,题解说了一句贪心。。。然后我怎么也想不明白是咋样的贪心法。。。可能也和我没认真读题解有关。。我想的是,每次选取s中最长的可以由t得到的子串,这样贪心肯定是对的。但问题是s中有很多这样的子串时,我们不知道挑哪个?我一时想不明白了。。要是有恰好路过的大牛,请不吝赐教~~说下我的做法吧,n = s.length(),用dp(i)表示s.substr(i, n)可以用的最少t的数目
然后我们预处理一发,用yu[i].se表示s从i出发,可以由t得到的最长子串的长度,yu[i].fi则表示这是从t的哪个位置出发得到的,再用yu[i].se的正负表示,是正着用的t还是反着用的
dp(i) = min(dp(i), dp(i+j + 1) + 1) 0 <= j <= yu[i].se
最后,还需要解决怎么得到yu[i]的,我们先对t的所有后缀和t反过来的所有后缀建立一个Trie树,然后用s从i出发的子串来顺着字典树匹配直到失陪,就是最大长度
注意,用邻接矩阵的Trie树的话,MAX一定要开够。。。不然就邻接表建树吧。。
实现
#include <bits/stdc++.h> using namespace std; const int maxn = 4500000; const int maxm = 2200; int trie[maxn][26]; int num = 1; int bgn[maxn]; string t,s; #define mp make_pair #define se second #define fi first #define pb push_back typedef pair<int,int> pii; void add1(int bg,int len){ int now = 0; for (int i=bg;i<=bg+len;i++){ int tmp = trie[now][t[i]-'a']; if (tmp != 0){ now = tmp; continue; } trie[now][t[i]-'a'] = num; now = num; num++; bgn[now] = bg+1; } } void add2(int bg,int len){ int now = 0; for (int i=bg;i>=bg-len;i--){ int tmp = trie[now][t[i]-'a']; if (tmp != 0){ now = tmp; continue; } trie[now][t[i]-'a'] = num; now = num; num++; bgn[now] = -bg-1; } } pii yu[maxm]; void dfs(int u,int dep,int bg){ if (bg+dep >= s.length() || trie[u][s[bg+dep]-'a'] == 0){ if (bgn[u] > 0){ yu[bg] = mp(bgn[u],dep-1); } else{ yu[bg] = mp(-bgn[u],-dep+1); } return; } dfs(trie[u][s[bg+dep]-'a'],dep+1,bg); } bool mm[26]; int dp[maxm]; int len[maxm]; int main(){ ios::sync_with_stdio(false); cin>>t>>s; for (auto ch:t){ mm[ch - 'a'] = 1; } int flag = 0; for (auto ch:s){ if (mm[ch-'a'] == 0){ flag = 1; break; } } if (flag){ puts("-1"); return 0; } for (int i=0;i<t.length();i++){ add1(i,t.length()-i-1); add2(i,i); } for (int i=0;i<s.length();i++){ dfs(0,0,i); } memset(dp,0x3f,sizeof(dp)); int n = s.length(); dp = 0; len = 0; for (int i=n-1;i>=0;i--){ for (int j=0;j<=abs(yu[i].se);j++){ if(dp[i] > dp[i+j+1] + 1){ dp[i] = dp[i+j+1] + 1; len[i] = j + 1; } } } cout << dp[0] <<endl; int now = 0; while (now < n){ if (yu[now].se >= 0) cout << yu[now].fi << " " << yu[now].fi + len[now] - 1 <<endl; else cout << yu[now].fi << " " << yu[now].fi - len[now] + 1 <<endl; now += len[now]; } return 0; }
相关文章推荐
- C 求字符数组最大值与次大值
- 软工课程总结
- SpringMVC的几种返回方式
- APP架构构思基本思路初稿
- c语言实现数组栈
- 学习之路
- 使用 Monit 监控PHP 服务中遇到的坑和解决办法
- 那些年我们一起做过的shell面试题(三)
- 数据结构_3:栈:STL
- 给编程初学者的干货:“秘籍”学好一本就不易
- android加密方式及原理
- 启动mysql 报错,,Starting MySQL.Manager of pid-file quit without updating fi[失败] (2011-10-28 12:30:56)转载▼
- 让人一用钟情的VS插件系列之一——Web Essentials(Web开发必备利器)
- 宽字符与窄字符的转换
- 深入理解 Javascript 面向对象编程
- Programming with ZooKeeper - A basic tutorial
- 2015总结与2016展望
- Spark部署配置
- 谓词函数
- shell---登录失败的IP添加到/etc/hosts.deny