daimayuan885 (字典树 字典树上DP)

image

  • 前缀和问题,考虑字典树
  • 由于字典树的存储结构,从上到下贪心是不行的
  • 但是可以从下往上:当前这个子树的大小小于等于k就不管它,等着上面一块处理,大于k就依次减去最大的子树,剩余的sz等着上面一块处理。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
//#define int long long
const int N = 3e5 + 5;
const int M = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
int n, k, tot = 1; 
int trie[N][26];
int ed[N], sz[N]; int ans;
void add ( string ss ) {
  int p = 1;
  for ( auto i : ss ) {
    int ch = i - 'a';
    if( ! trie[p][ch] ) {
      trie[p][ch] = ++ tot;
    }
    p = trie[p][ch];
  }
  ++ ed[p];
}
void dfs ( int p ) {
  sz[p] += ed[p];
  vector<int> ve;
  for ( int i = 0; i < 26; ++ i ) {
    int ne = trie[p][i];
    if( ne ) dfs( ne ), ve.push_back( sz[ne] ), sz[p] += sz[ne];
  }
  if( sz[p] <= k) return;
  sort( ve.begin(), ve.end(), []( int A, int B ){ return A > B; } );

  for ( auto i : ve) {
    ++ ans; sz[p] -= i;
    if(sz[p] <= k) break;
  }
}
int main () {
  IOS;
  cin >> n >> k;
  for ( int i = 1; i <= n; ++ i ) {
    string ss; cin >> ss;
    add(ss);
  }
  dfs(1);
  cout << ans + (sz[1] > 0) << '\n'; // + 剩余的一块处理
  return 0;
}
posted @ 2022-05-12 10:58  qingyanng  阅读(36)  评论(0编辑  收藏  举报