トピックリンク
まず、我々はデータの複数の文字列を入力して、だけでなく、共通のプレフィックスを求めて、考えるのは簡単です、この質問される(トライ\)\アプリケーションを
我々は(トライ\)\ツリーが構築され、上記ツリーに走った\(DP \)することができます。
すなわち\(DP(U、DIS) \) で表される\(U \)サブツリーのルートであり、\(U \)深さ\(DIS \)答えたとき
簡単に考えることができ、被験者によって定義される、\(DP(U、DIS)= maxの\ {DIS TOT * [U]、DP(V、+ DIS 1)\} \)
\(TOTは、[U] \)である(U \)\するルートサブツリーのリーフノードの数(すなわち、ルートノード(U \)\共通プレフィックスの期間を、この文字列は、共通の接頭辞を有します量\(TOT [U] \) )
だから我々は、プライマリコードを期待することができます。
#include <bits/stdc++.h>
using namespace std;
struct Trie{
static const int maxnode = 100100;
static const int sigma_size = 2;
int ch[maxnode][sigma_size];
int val[maxnode];
int sz;
inline void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
Trie(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
inline int idx(char c){return c - '0';}
inline void insert(const string &s){
int u = 0,n = s.size();
for(int i = 0;i < n;i++){
int c = idx(s[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u]++;
}
inline int tot(int u){
int ret = val[u];
for(int c = 0;c < sigma_size;c++)
if(ch[u][c])ret += tot(ch[u][c]);
return ret;
}
inline int dfs(int u,int dis){
int ret = dis * tot(u);
for(int c = 0;c < sigma_size;c++)
if(ch[u][c])ret = max(ret,dfs(ch[u][c],dis + 1));
return ret;
}
}tt;
string ss;
int T,n;
inline void solve(){
tt.init();
cin >> n;
for(int i = 1;i <= n;i++){
cin >> ss;
tt.insert(ss);
}
printf("%d\n",tt.dfs(0,0));
}
int main(){
ios::sync_with_stdio(false);
cin >> T;
while(T--)
solve();
return 0;
}
走っコード160ミリ秒は、タイムアウトしませんが、我々はまだ最適化を検討してください。
すべての\(DP \)が考えられている\(TOT \) 、時間、その場で複雑爆発(データ無害H2Oが、)。
それから
私たちは、構築することができます\(トライ\)とき、ツリーを\(TOT \)の配列を把握します。
通常建て\に(トライ\)ツリーのリーフノードは、この質問では、我々は実績があり、その上のポイントを置くすべての重みを値をエンパワーすることです\(+ 1 \) 、この権利は、各ノードの値にありますサブツリーのルートノードにリーフノードの数
コード:
#include <bits/stdc++.h>//懒得打了,大家最好别用万能头文件
using namespace std;
struct Trie{
static const int maxnode = 100100;//最大节点数
static const int sigma_size = 2;//字符集大小
int ch[maxnode][sigma_size];//儿子数组
int val[maxnode];//节点附加权值,即转移方程的tot数组
int sz;//当前节点总数
inline void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}//初始化函数
Trie(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
inline int idx(char c){return c - '0';}
inline void insert(const string &s){//插入字符串,传引用避免拷贝开销
int u = 0,n = s.size();
for(int i = 0;i < n;i++){
int c = idx(s[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
val[u]++;//这里即上文所说的统计子树节点个数
}
}
inline int dfs(int u,int dis){//最终答案
int ret = val[u] * dis;
for(int c = 0;c < sigma_size;c++)
if(ch[u][c])
ret = max(ret,dfs(ch[u][c],dis + 1));
return ret;
}
}tt;
string ss;
int T,n;
inline void solve(){//多组数据求解
tt.init();
cin >> n;
for(int i = 1;i <= n;i++){
cin >> ss;
tt.insert(ss);
}
printf("%d\n",tt.dfs(0,0));
}
int main(){
ios::sync_with_stdio(false);
cin >> T;
while(T--)
solve();
return 0;
}