1. 程式人生 > >CodeForces 1082 F Speed Dial

CodeForces 1082 F Speed Dial

題目傳送門

題意:現在有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+7; const int N = 1e5 + 100; struct Node{ int son[10]; int deep; int cnt; Node(){ memset(son, -1, sizeof(son)); cnt = deep = 0; } }Trie[505]; int dp[505][15][505]; int dp2[505][15][505][15]; char s[N]; int tot = 0; void add(){ int now = 0, cnt; scanf("%s%d", s, &cnt); int len = strlen(s); for(int i = 0; i < len; ++i){ int to = s[i] - '0'; if(Trie[now].son[to] == -1){ Trie[now].son[to] = ++tot; Trie[tot].deep = Trie[now].deep + 1; } now = Trie[now].son[to]; } Trie[now].cnt += cnt; } int dfs(int x, int rem, int fa){ if(dp[x][rem][fa] != -1) return dp[x][rem][fa]; dp[x][rem][fa] = inf; if(rem) dp[x][rem][fa] = min(dfs(x, rem-1, x), dp[x][rem][fa]); vector<int> ch; for(int i = 0; i < 10; ++i) if(Trie[x].son[i] != -1) ch.pb(Trie[x].son[i]); dp2[x][rem][fa][ch.size()] = 0; for(int i = int(ch.size())-1; i >= 0; --i){ for(int j = 0; j <= rem; ++j){ dp2[x][rem][fa][i] = min(dp2[x][rem][fa][i], dp2[x][rem-j][fa][i+1] + dfs(ch[i], j, fa)); } } dp[x][rem][fa] = min(dp[x][rem][fa], dp2[x][rem][fa][0]+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 = 1, v; i <= n; ++i) add(); memset(dp, -1, sizeof(dp)); memset(dp2, inf, sizeof(dp2)); int ans = dfs(0,k,0); cout << ans << endl; return 0; }
View Code