1. 程式人生 > >[UVa 11732] "strcmp()"Anyone?

[UVa 11732] "strcmp()"Anyone?

print clu any TP head cas mes 處理 scan

Link:

UVa 11732 傳送門

Solution:

思路還是很套路:建$Trie$樹,在$Trie$樹上跑一遍統計答案

(統計答案時註意將葉節點特殊處理,同時對於$e(u,v)$用$val[v]*(val[u]-val[v])$來統計個數)

重點在於此題的存儲方式:左兒子右兄弟存儲法 (鏈表式存儲法)

由於此題節點數$MAXN=4e6$,如果按照$ch[MAXN][27]$建圖剛好$MLE$

而鏈表式存儲法優點就在於省空間,不用建立多余的節點,只不過犧牲了查詢的效率

實現起來很像鏈式前向星:$ls[i]$相當於$head[i]$,$rb[i]$相當於$nxt[i]$,每次插入也是從頭部

插入

Tip:在處理過程中將數據初始化,盡量不用$memset$

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN=4e6+10;
char s[1005],ch[MAXN];ll res=0;
int T,n,ls[MAXN],rb[MAXN],val[MAXN],cnt=0;

void insert()
{
    int len=strlen(s);
    int u=0,v;val[0]++;
    for(int i=0;i<=len;i++)
    {
        
bool f=false; for(v=ls[u];v;v=rb[v]) if(ch[v]==s[i]){f=true;break;} if(!f) { v=++cnt;ch[v]=s[i]; //建立新節點 rb[v]=ls[u];ls[u]=v; ls[v]=0;val[v]=0; } u=v;val[u]++; } } void dfs(int dep,int u) { if(!ls[u]){res+=1ll*val[u]*(val[u]-1
)*dep;return;} //統計葉節點的答案 ll sum=0;int v; for(v=ls[u];v;v=rb[v]) //統計答案 sum+=val[v]*(val[u]-val[v]); res+=1ll*sum/2*(2*dep+1); for(v=ls[u];v;v=rb[v]) dfs(dep+1,v); } int main() { while(scanf("%d",&n)==1 && n) { cnt=0;val[0]=ls[0]=rb[0]=0; for(int i=1;i<=n;i++) scanf("%s",s),insert(); res=0;dfs(0,0); printf("Case %d: %lld\n",++T,res); } return 0; }

[UVa 11732] "strcmp()"Anyone?