题目传送门

题意:现在有n个电话号码,每个电话号码为si,拨打次数为pi。 现在有k 个快捷键,每次拨打号码之前可以先按一次快捷键,然后再输入数字,现在问输入数字次数是多少。快捷键的号码可以不在电话簿上。

题解:

先构建一个字典树,然后在字典树上进行DP。

dp[x][rem][fa]  x -> 节点x  rem -> 还有rem次快捷键次数 fa 最近的那个父亲用了这个快捷键

dp2[x][rem][fa][i]  前面和上面一样 i代表的是处理到i这个节点的最优花费。

dp[x][rem][fa]为可以包含x的最优花费。

dp2[x][rem][fa][i]为不可以包含x的最优花费。

转移方式:

1. 当rem > 1的时候  我们可以用 dp[x][rem-1][x]  转移到 dp[x][rem][fa]

2. 对于 dp2[x][rem][fa][i] 我们可以用  dp2[x][rem-j][fa][i+1] + dp[ch[i]][j][fa] 转移过来。

3. 对于 dp[x][rem][fa][i] 我们可以用 dp[2][x][rem][0] + (deep[x] - deep[fa]) * cnt[x] 转移过来。

简单的来说, 就是对以x为根的树来说, 我们可以用子树上的状态转移过来。

需要注意的有2个点:

1 记忆化转移, 因为会有很多的点的状态是重复的。

2 先把小次数的算出来, 因为在大次数的转移的过程中需要用的小次数的值。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
struct Node{
int son[];
int deep;
int cnt;
Node(){
memset(son, -, sizeof(son));
cnt = deep = ;
}
}Trie[];
int dp[][][];
int dp2[][][][];
char s[N];
int tot = ;
void add(){
int now = , cnt;
scanf("%s%d", s, &cnt);
int len = strlen(s);
for(int i = ; i < len; ++i){
int to = s[i] - '';
if(Trie[now].son[to] == -){
Trie[now].son[to] = ++tot;
Trie[tot].deep = Trie[now].deep + ;
}
now = Trie[now].son[to];
}
Trie[now].cnt += cnt;
}
int dfs(int x, int rem, int fa){
if(dp[x][rem][fa] != -) return dp[x][rem][fa];
dp[x][rem][fa] = inf;
if(rem) dp[x][rem][fa] = min(dfs(x, rem-, x), dp[x][rem][fa]);
vector<int> ch;
for(int i = ; i < ; ++i)
if(Trie[x].son[i] != -)
ch.pb(Trie[x].son[i]);
dp2[x][rem][fa][ch.size()] = ;
for(int i = int(ch.size())-; i >= ; --i){
for(int j = ; j <= rem; ++j){
dp2[x][rem][fa][i] = min(dp2[x][rem][fa][i], dp2[x][rem-j][fa][i+] + dfs(ch[i], j, fa));
}
}
dp[x][rem][fa] = min(dp[x][rem][fa], dp2[x][rem][fa][]+Trie[x].cnt*(Trie[x].deep - Trie[fa].deep));
return dp[x][rem][fa];
}
int main(){
int n, k;
scanf("%d%d", &n, &k);
for(int i = , v; i <= n; ++i)
add();
memset(dp, -, sizeof(dp));
memset(dp2, inf, sizeof(dp2));
int ans = dfs(,k,);
cout << ans << endl;
return ;
}

最新文章

  1. C# 小知识
  2. Notes:indexedDB使用
  3. ffmpeg 音频转换: use ffmpeg convert the audio from stereo to mono without changing the video part
  4. 重写HashMap
  5. 浅谈TCP优化
  6. scala Option 里的 orNull orElse getOrElse 区别和使用
  7. TableLayoutPanel 的使用
  8. 38.利用接口做参数,写个计算器,能完成+-*/运算 (1)定义一个接口Compute含有一个方法int computer(int n,int m); (2)设计四个类分别实现此接口,完成+-*/运算 (3)设计一个类UseCompute,含有方法: public void useCom(Compute com, int one, int two) 此方法要求能够:1.用传递过来的对象调用comp
  9. PHP连接数据库:封装成类
  10. 【Luogu1414】又是毕业季II(数论)
  11. 【构造】UVa 11387 The 3-Regular Graph
  12. 使用 ASP.NET Core MVC 创建 Web API(五)
  13. 30分钟,让你彻底明白Promise原理
  14. QT_REQUIER_CONFIG
  15. (HDU 1542) Atlantis 矩形面积并——扫描线
  16. JavaScript for...in 循环
  17. 09_组件三大属性(3)_refs和事件处理
  18. UWP开发细节记录:判断文件类型
  19. PAT-GPLT L1-039 - 古风排版 - [字符串输入输出]
  20. Java编程练习题

热门文章

  1. Android Studio &quot;cannot resolve symbol R&quot; 问题
  2. win10去除快捷方式小箭头
  3. solr 新建core
  4. Struts2 中Struts.xml结果页面配置
  5. js获得页面get跳转的参数
  6. css3加js做一个简单的3D行星运转效果
  7. Hystrix超时测试
  8. JAVA基础知识(六)Java 静态多分派&amp;动态单分派
  9. HTML/CSS:display:flex 布局教程
  10. 算法与数据结构基础 - 位运算(Bit Manipulation)