題目鏈接:http://codeforces.com/contest/467/problem/D
題目描述:給你m 個單詞,n 種替換操作,每種操作有兩個字符串 a b,表示可以將a 替換成 b。然後讓你計算替換之後 的m 個單詞中'r'最少有多少個,在‘r'最少的情況下,m個單詞的總長度最短是多少?(注:單詞不區分大小寫!!!)
解題思路:思路還是比較好想。可以先將n 個替換操作 中的字符串全都hash,然後建一個有向圖,a能被b替換,則由a向b引一條邊,然後跑一邊強連通。在一個強連通分量裏面的點一定可以相互到達,然後縮點,這時候,圖中就沒有環了(這是非常好的),剩下的就是一個記憶化搜索吧(隨便搞一搞就能過。。)
反思,我寫的代碼實在太挫了。。。代碼太長
另外,圖論太差了。。。真心不懂那些算法,只會敲版。。。還要多練
//#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
#define lson k<<1
#define rson k<<1|1
using namespace std;
const int N = 500005;
const int MAXN = 500010;
vector<int> link[MAXN];
int mem[MAXN], stk[MAXN], depth[MAXN];
int sum, num;
bool mark[MAXN], used[MAXN];
void dfs(int k, int deep)
{
int min, i;
min = depth[k] = deep;
used[k] = 1;
stk[sum++] = k;
for (i = 0; i < link[k].size(); i++)
{
if (mark[link[k][i]]) continue;
if (!used[link[k][i]]) dfs(link[k][i], deep + 1);
if (min > depth[link[k][i]]) min = depth[link[k][i]];
}
if (depth[k] > min)
{
depth[k] = min;
return;
}
while (stk[sum - 1] != k)
{
mem[stk[sum - 1]] = num;
mark[stk[sum - 1]] = 1;
sum--;
}
mark[k] = 1;
mem[k] = num;
sum--;
num++;
}
map<string,int> mp;
char str[N];
string s[N];
string pt[N<<1];
int cnt[N][2];
map<pair<int,int>,int> mpp;
vector<int> v[N];
bool vis[N];
void dfs_ans(int k)
{
vis[k]=true;
int sz=v[k].size();
int length=cnt[k][0],cntr=cnt[k][1];
for(int i=0;i<sz;i++)
{
int to=v[k][i];
if(!vis[to]) dfs_ans(to);
int len=cnt[to][0],r=cnt[to][1];
if(r<cntr)
{
cntr=r,length=len;
}else if(r==cntr&&len<length)
{
length=len;
}
}
cnt[k][0]=length,cnt[k][1]=cntr;
}
void calc(string t,int &r,int &len)
{
len=t.size();
r=0;
for(int i=0;i<len;i++) if(t[i]=='r') r++;
}
int main()
{
#ifdef PKWV
freopen("in.in", "r", stdin);
#endif // PKWV
int m;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%s",str);
for(int j=0;str[j];j++) str[j]|=0x20;
s[i]=str;
}
int n;
scanf("%d",&n);
int lx=1;
for(int i=0;i<n;i++)
{
scanf("%s",str);
for(int j=0;str[j];j++) str[j]|=0x20;
string t=str;
int t1=mp[t];
if(t1==0)
{
pt[lx]=t;
t1=mp[t]=lx++;
}
scanf("%s",str);
for(int j=0;str[j];j++) str[j]|=0x20;
t=str;
int t2=mp[t];
if(t2==0)
{
pt[lx]=t;
t2=mp[t]=lx++;
}
link[t1].PB(t2);
}
for(int i=1;i<lx;i++)
{
if(!used[i]) dfs(i,0);
}
for(int i=1;i<lx;i++)
{
int t=mem[i];
int r,len;
calc(pt[i],r,len);
if(cnt[t][0]==0)
{
cnt[t][0]=len,cnt[t][1]=r;
}
else
{
if(r<cnt[t][1])
{
cnt[t][1]=r,cnt[t][0]=len;
}else if(cnt[t][1]==r&&len<cnt[t][0])
{
cnt[t][0]=len;
}
}
}
int ly=1;
for(int i=1;i<lx;i++)
{
int t=mem[i];
int sz=link[i].size();
for(int j=0;j<sz;j++)
{
int tt=mem[link[i][j]];
if(t==tt) continue;
if(mpp[make_pair(t,tt)]==0)
{
v[t].PB(tt);
mpp[make_pair(t,tt)]=ly++;
}
}
}
for(int i=1;i<lx;i++)
{
if(!vis[mem[i]])
{
dfs_ans(mem[i]);
}
}
int ct=0;
ll len=0;
for(int i=0;i<m;i++)
{
if(mp[s[i]])
{
int t=mem[mp[s[i]]];
len+=cnt[t][0],ct+=cnt[t][1];
}else
{
int sz=s[i].size();
for(int j=0;j<sz;j++) if(s[i][j]=='r') ct++;
len+=sz;
}
}
printf("%d %I64d\n",ct,len);
return 0;
}