您的位置:首页 > Web前端

Codeforces 467D. Fedor and Essay (Graphs,dfs,dp,hashing,strings,图论综合型好题)

2014-09-21 04:21 411 查看
D. Fedor and Essay

time limit per test
2 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

After you had helped Fedor to find friends in the «Call of Soldiers 3» game, he stopped studying completely. Today, the English teacher told him to prepare an essay. Fedor didn't want to prepare the essay, so he asked Alex for help. Alex came to help and wrote
the essay for Fedor. But Fedor didn't like the essay at all. Now Fedor is going to change the essay using the synonym dictionary of the English language.

Fedor does not want to change the meaning of the essay. So the only change he would do: change a word from essay to one of its synonyms, basing on a replacement rule from the dictionary. Fedor may perform this operation any number of times.

As a result, Fedor wants to get an essay which contains as little letters «R» (the case doesn't matter) as possible. If there are multiple essays with minimum
number of «R»s he wants to get the one with minimum length (length of essay is the sum of the lengths of all the words in it). Help Fedor get the required essay.

Please note that in this problem the case of letters doesn't matter. For example, if the synonym dictionary says that word cat can
be replaced with word DOG, then it is allowed to replace the word Cat with
the word doG.

Input

The first line contains a single integer m (1 ≤ m ≤ 105) —
the number of words in the initial essay. The second line contains words of the essay. The words are separated by a single space. It is guaranteed that the total length of the words won't exceed 105 characters.

The next line contains a single integer n (0 ≤ n ≤ 105) —
the number of pairs of words in synonym dictionary. The i-th of the next n lines
contains two space-separated non-empty words xi and yi.
They mean that word xi can
be replaced with word yi (but
not vise versa). It is guaranteed that the total length of all pairs of synonyms doesn't exceed 5·105 characters.

All the words at input can only consist of uppercase and lowercase letters of the English alphabet.

Output

Print two integers — the minimum number of letters «R» in an optimal essay and the minimum length of an optimal essay.

Sample test(s)

input
3
AbRb r Zz
4
xR abRb
aA xr
zz Z
xr y


output
2 6


input
2
RuruRu fedya
1
ruruRU fedor


output
1 10


题目地址:http://codeforces.com/contest/467/problem/D

别怪我=。=

我本来是写好了题解的,结果按错一个键,题解没有保存下来。

懒,不写了。总的来说方法就是标题所列,那也是codeforces上tag所给

方法如下:

hashing + strings: 有效hash处理字符串,将字符串转换为点,方便图形处理(要以字符串种类为基建图,否则边会太多,数组存不下

graphs:  图论,用到建图等图论知识

SCC: 强联通分量,将图转换为有向无环图(直接处理图会出错,必须转换为有向无环图

dfs+dp: 在有向无环图上进行dfs,在dfs基础上dp,进行搜索

最后统计答案即可

看不懂就抱歉了,不小心没保存题解

据说这题有更好的方法?我要去学学,哪天心血来潮再把题解补上吧=。=!

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi 3.1415926535898
#define eps 1e-6
#define MOD 1000000007
#define MAXN 100100
#define N
#define M
int m,n;
//下面的是用于原图的,即没有SCC之前的图
struct Vertex
{
ll len,numr;
}ver[3*MAXN];
int num_ver;
struct Edge
{
int to,next,from;
}edge[10*MAXN];
int w,head[3*MAXN];
void build_edge(int from,int to)
{
w++;
edge[w].from=from;
edge[w].to=to;
edge[w].next=head[from];
head[from]=w;
}
map<string,int>mymap;
map<string,int>::iterator it,it1,it2;
ll numr;
string makelowercasestring(string s)
{//将string全部转为小写,顺便统计 r 的个数
int len=slen(s);
string res;
res.clear();
numr=0;
rep(i,0,len)
{
if(isupper(s[i])) s[i]=s[i]-'A'+'a';
res+=s[i];
if(s[i]=='r') numr++;
}
return res;
}
void makemap(string s,int t)
{
mymap.insert(pair<string,int>(s,t));
}
int pre[3*MAXN],lowlink[3*MAXN],sccbelong[3*MAXN];
ll sccnum[3*MAXN];
int dfs_clock,scc_cnt;
stack<int>st;
void tarjan(int now)
{//缩点,将图变成有向无环图
pre[now]=lowlink[now]=++dfs_clock;
st.push(now);
int i,to;
for(i=head[now];i!=-1;i=edge[i].next)
{
to=edge[i].to;
if(!pre[to])
{
tarjan(to);
lowlink[now]=min(lowlink[now],lowlink[to]);
}
else if(!sccbelong[to])
{
lowlink[now]=min(lowlink[now],pre[to]);
}
}
if(lowlink[now]==pre[now])
{
scc_cnt++;
int x;
do
{
x=st.top();
st.pop();
sccbelong[x]=scc_cnt;
sccnum[scc_cnt]++;
}while(now!=x);
}
}
//下面是用于强联通分量的图,用于新图的
struct Vertextarjan
{
ll len,numr;
}vertarjan[3*MAXN];
int num_verr;
struct Edgetarjan
{
int to,next,from;
}edgetarjan[10*MAXN];
int headtarjan[3*MAXN],ww;
void build_edgetarjan(int from,int to)
{
ww++;
edgetarjan[ww].from=from;
edgetarjan[ww].to=to;
edgetarjan[ww].next=headtarjan[from];
headtarjan[from]=ww;
}
bool vis[3*MAXN];
void dfs(int now)
{//dfs搜答案,动态规划处理
vis[now]=true;
int i,to;
for(i=headtarjan[now];i!=-1;i=edgetarjan[i].next)
{
to=edgetarjan[i].to;
if(!vis[to]) dfs(to);
if(vertarjan[now].numr>vertarjan[to].numr)
{
vertarjan[now].numr=vertarjan[to].numr;
vertarjan[now].len=vertarjan[to].len;
}
else if(vertarjan[now].numr==vertarjan[to].numr && vertarjan[now].len>vertarjan[to].len)
{
vertarjan[now].len=vertarjan[to].len;
}
}
}
string forinput[3*MAXN];//记录输入,统计答案用
int main()
{
cin>>m;
string s;
mymap.clear();
num_ver=0;
repin(i,1,m)
{
cin>>s;
s=makelowercasestring(s);
forinput[i]=s;
it=mymap.find(s);
if(it!=mymap.end()) continue;//由于以种类为基建图,所以同种类型只让其出现一次
makemap(s,++num_ver);
int t=num_ver;
ver[t].len=slen(s);
ver[t].numr=numr;
}
cin>>n;
string sx,sy;
int x,y;
w=0;
clr_minus1(head);
//下面,字符串hash后,以字符串种类为单位建图
repin(ii,1,n)
{
cin>>sx>>sy;
sx=makelowercasestring(sx);
it=mymap.find(sx);
if(it==mymap.end())
{
makemap(sx,++num_ver);
int t=num_ver;
ver[t].len=slen(sx);
ver[t].numr=numr;
it=mymap.find(sx);
}
x=it->second;
sy=makelowercasestring(sy);
it=mymap.find(sy);
if(it==mymap.end())
{
makemap(sy,++num_ver);
int t=num_ver;
ver[t].len=slen(sy);
ver[t].numr=numr;
it=mymap.find(sy);
}
y=it->second;
build_edge(x,y);
}
//此时,所有的点和边都适当地建立好了
//下面就开始SCC,将图变成有向无环图
dfs_clock=scc_cnt=0;
repin(i,1,num_ver)
{
if(!pre[i]) tarjan(i);
}
//下面将tarjan出来的有向无环图建立起来
vector<int>belong[3*MAXN];
//记录每个点属于哪一个强联通分量
repin(i,1,num_ver)
{
int be=sccbelong[i];
belong[be].pb(i);
}
ll len=1;
num_verr=0;
//下面这一步很重要
//将每个强联通分量构建出来,其numr和len值来源于其中的点
//找到其中点numr最小的那个,numr一样找len最小那个,那个点就代表着这个强联通分量,相当于其他点都视为那个最优点
repin(ii,1,scc_cnt)
{
int len1=gsize(belong[ii]);
bool first=true;
rep(j,0,len1)
{
int i=belong[ii][j];
if(first)
{
first=false;
len=ver[i].len;
numr=ver[i].numr;
continue;
}
if(ver[i].numr<numr)
{
numr=ver[i].numr;
len=ver[i].len;
}
else if(ver[i].numr==numr && ver[i].len<len)
{
len=ver[i].len;
}
}
num_verr++;//ii==num_verr
vertarjan[ii].len=len;
vertarjan[ii].numr=numr;
}
//点建好了,根据之前的边的关系找桥,实际上就是找割点,通过桥构建新图的边
//这是将图转换为有向无环图的重要有效方法
clr_minus1(headtarjan);
ww=0;
int from,to;
repin(i,1,w)
{
from=edge[i].from;
to=edge[i].to;
if(sccbelong[from]!=sccbelong[to])
{
int x1=sccbelong[from],x2=sccbelong[to];
build_edgetarjan(x1,x2);
}
}
//dfs+dp搜
repin(i,1,num_verr)
{
if(!vis[i]) dfs(i);
}
//统计答案
ll ans1=0,ans2=0;
int be,wh;
repin(i,1,m)
{//对于输入的这个字符串来说,找到它属于的强联通分量,SCC的答案就是它的答案
//注意建图时候是以种类为基来建图的,但一个种类的字符串可能代表很多个字符串,注意这里
s=forinput[i];
wh=mymap[s];
be=sccbelong[wh];
ans1+=vertarjan[be].numr;
ans2+=vertarjan[be].len;
}
printf("%lld %lld\n",ans1,ans2);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: