CF467D Fedor and Essay 有向图强连通分量+缩点
一.题目
传送门
翻译:
在你帮助Fedor在«Call of Soldiers 3»这款游戏中找到朋友之后,他完全停止了学习。今天,英语老师让他准备一篇文章。 Fedor并不想准备这篇文章,所以他向Alex寻求帮助。Alex来帮忙并为Fedor写了一篇文章。但Fedor根本不喜欢这篇文章。现在Fedor将使用英语同义词词典来重写文章。
Fedor不想改变文章的含义。因此,他将做的唯一改变是:根据字典中的替换规则,将一个论文中的单词改为它的一个同义词。 Fedor可以多次执行此操作。
因此,Fedor希望得到一篇文章,其中包含尽可能少的字母“R”(样例无关)。如果有多篇论文都有最小数量的“R”,那么他希望得到一个最小长度的论文(论文的长度是其中所有单词长度的总和)。帮助Fedor获得所需的论文。
请注意,在这个问题中,字母的大小写情况无关紧要。例如,如果同义词词典说单词cat可以用单词DOG替换,则允许用单词doG替换单词Cat。
二.题解
乍一看一个字符串的题跟强连通分量有什么关系?QWQ
其实关系大。对于每一个单词向可以替换它的单词连一条有向边,每个单词内r的数量即点权,然后我们用存每个连通块内的单词中字母r的最少个数,用存每个连通块内的单词的最短长度。
先做一遍Tarjan求有向图强连通分量,然后再缩点做一个树形DP,用来更新。这道题就愉快地解决了。
至于存单词,用map就行了。
三.Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>
#include <map>
using namespace std;
#define M 500005
#define LL long long
int n, m, dfn[M], low[M], cnt, num, val[M], len[M], sz, minn1[M], minn2[M], belong[M], id[M];
bool vis[M], instack[M];
LL ans1, ans2;
vector <int> G[M];
vector <int> G1[M];
stack <int> s;
map <string, int> mp;
void Tarjan (int x){
dfn[x] = low[x] = ++ cnt;
s.push(x);
instack[x] = 1;
for (int i = 0; i < G[x].size(); i ++){
int tmp = G[x][i];
if (! dfn[tmp]){
Tarjan (tmp);
low[x] = min (low[x], low[tmp]);
}
else if (instack[tmp]){
low[x] = min (low[x], dfn[tmp]);
}
}
if (low[x] == dfn[x]){
num ++;
int v;
do{
v = s.top();
s.pop();
instack[v] = 0;
belong[v] = num;
if (val[v] < minn1[num] || (val[v] == minn1[num] && len[v] < minn2[num]))
minn1[num] = val[v], minn2[num] = len[v];
}while (v != x);
}
}
void dp (int x){
if (vis[x])
return ;
vis[x] = 1;
for (int i = 0; i < G1[x].size(); i ++){
int tmp = G1[x][i];
dp (tmp);
if (minn1[tmp] < minn1[x])
minn1[x] = minn1[tmp], minn2[x] = minn2[tmp];
else if (minn1[tmp] == minn1[x])
minn2[x] = min (minn2[x], minn2[tmp]);
}
}
int main (){
memset (minn1, 0x3f, sizeof minn1);
memset (minn2, 0x3f, sizeof minn2);
scanf ("%d", &m);
for (int i = 1; i <= m; i ++){
char ch[M];
scanf ("%s", ch);
int l = strlen (ch), ns = 0;
for (int j = 0; j < l; j ++){
if (ch[j] >= 'A' && ch[j] <= 'Z') ch[j] = ch[j] - 'A' + 'a';
if (ch[j] == 'r') ns ++;
}
int t = mp[ch];
if (! t)
mp[ch] = t = ++ sz;
val[t] = ns, len[t] = l;
id[i] = t;
}
scanf ("%d", &n);
for (int i = 1; i <= n; i ++){
char ch[M];
scanf ("%s", ch);
int x = strlen (ch), s = 0;
for (int j = 0; j < x; j ++){
if (ch[j] >= 'A' && ch[j] <= 'Z') ch[j] = ch[j] - 'A' + 'a';
if (ch[j] == 'r') s ++;
}
int t1 = mp[ch];
if (! t1)
mp[ch] = t1 = ++ sz;
val[t1] = s, len[t1] = x;
scanf ("%s", ch);
x = strlen (ch), s = 0;
for (int j = 0; j < x; j ++){
if (ch[j] >= 'A' && ch[j] <= 'Z') ch[j] = ch[j] - 'A' + 'a';
if (ch[j] == 'r') s ++;
}
int t2 = mp[ch];
if (! t2)
mp[ch] = t2 = ++ sz;
val[t2] = s, len[t2] = x;
G[t1].push_back (t2);
}
for (int i = 1; i <= sz; i ++)
if (! dfn[i])
Tarjan (i);
for (int i = 1; i <= sz; i ++){
for (int j = 0; j < G[i].size (); j ++){
int tmp = G[i][j];
if (belong[i] != belong[tmp])
G1[belong[i]].push_back (belong[tmp]);
}
}
for (int i = 1; i <= num; i ++)
dp (i);
for (int i = 1; i <= m; i ++)
ans1 = ans1 + 1ll * minn1[belong[id[i]]], ans2 = ans2 + 1ll * minn2[belong[id[i]]];
printf ("%lld %lld\n", ans1, ans2);
return 0;
}
浙公网安备 33010602011771号