H-Modify Minieye杯第十五届华中科技大学程序设计邀请赛现场赛
题面见 https://ac.nowcoder.com/acm/contest/700#question
题目大意是有n个单词,有k条替换规则(单向替换),每个单词会有一个元音度(单词里元音的个数)和长度,现在希望利用替换规则(每个规则可使用无限次或不用)将每个单词替换成元音度值最小的单词,如果有多个单词元音度同等最小,那么取长度最小的单词。最后输出替换后的n个单词的元音度值之和与长度之和。
单纯每个点暴力搜,无疑会有爆复杂度的风险 1e5*1e5 ,如果记录搜过的点之后不搜,也会有在一个强连通分量里最早的点能搜到最优解,而后来的点无法get到这个最有解。
于是我们可以用Tarjan求scc后缩点,然后在缩点之后的分量图开始DFS。因为这个分量图是绝对无环的图,所以可以在不重复搜点下得到最优解。
比赛时 替换最优解的判断写错了,昏了头把长度的比较搞错。然后此题还有一个坑点,就是开始给的n个单词中可能会有重复,不能直接由string映射至点号。
比赛时代码修改后的通过版本:
#include<bits/stdc++.h> using namespace std;
#define IsVow(i) ((i)=='a'||(i)=='e'||(i)=='i'||(i)=='o'||(i)=='u')
typedef long long ll; const int maxn=+;
struct Edge{
int from,to;
int nxt;
};
struct word{
int vow,len;
}voc[maxn], syno[maxn];;
bool vis[maxn];
int head[maxn],tot;
Edge edges[maxn];
map<string , int > dict;
string ori[maxn];
int DFN[maxn],LOW[maxn],STACK[maxn],Belong[maxn];
int scc,dfs_no,top;
bool Instack[maxn];
vector< vector< int > > G(maxn, vector<int>() ); void addedge(int u,int v){
edges[tot].from=u;
edges[tot].to=v;
edges[tot].nxt=head[u];
head[u]=tot++;
} word make_word(string & s){
int cnt=;
word ans;
ans.len=(int) s.size();
for(auto const& i:s)
if(IsVow(i)) cnt++;
ans.vow=cnt;
return ans;
} void Tarjan(int u){
LOW[u]=DFN[u]=++dfs_no;
STACK[++top]=u;
Instack[u]=true;
for(int i=head[u];i!=-;i=edges[i].nxt){
int v=edges[i].to;
if(!DFN[v]){
Tarjan(v);
LOW[u]=min(LOW[u],LOW[v]);
}
else if(Instack[v])
LOW[u]=min(LOW[u],DFN[v]);
}
if(LOW[u]==DFN[u]){
scc++;
syno[scc]=(word){,};
while(STACK[top]!=u){
int v=STACK[top];
if(voc[v].vow < syno[scc].vow)
{
syno[scc].vow=voc[v].vow;
syno[scc].len=voc[v].len;
}
else if( syno[scc].vow == voc[v].vow)
syno[scc].len=min(syno[scc].len,voc[v].len); Instack[STACK[top]]=false;
Belong[STACK[top--]]=scc; }
Instack[u]=false;
Belong[u]=scc;
top--;
if(voc[u].vow < syno[scc].vow)
{
syno[scc].vow=voc[u].vow;
syno[scc].len=voc[u].len;
}
else if( syno[scc].vow == voc[u].vow)
syno[scc].len=min(syno[scc].len,voc[u].len);
}
} void DFS(int ind){
//cout<<ind<<":"<<syno[ind].vow<<" , "<<syno[ind].len<<endl;
if(vis[ind]){
return ;
}
vis[ind]=true; for(int i=;i<G[ind].size();++i){
int nxind=G[ind][i];
DFS(nxind);
if(syno[nxind].vow < syno[ind].vow)
{
syno[ind].vow=syno[nxind].vow;
syno[ind].len=syno[nxind].len;
}
else if( syno[nxind].vow == syno[ind].vow)
syno[ind].len=min(syno[ind].len,syno[nxind].len);
}
} int main(){
ios::sync_with_stdio(false);cin.tie();
memset(head,-,sizeof(head));
tot=;
int n,k;
cin>>n;
int TOT=;
for(int i=;i<=n;++i){
string tmp;
cin>>tmp;
ori[i]=tmp;
if(dict.count(tmp)==){
dict[tmp]=++TOT;
voc[dict[tmp]]=make_word(tmp);
}
}
cin>>k;
//cout<<"N:K:"<<n<<k<<endl;
for(int i=;i<k;++i){
string frm,to;
cin>>frm>>to;
if(dict.count(frm)==) {dict[frm]=++TOT;voc[dict[frm]]=make_word(frm);}
if(dict.count(to)==) {dict[to]=++TOT;voc[dict[to]]=make_word(to);}
addedge(dict[frm],dict[to]);
}
scc=;
for(int i=;i<=n;++i)
if(!DFN[i])
Tarjan(i);
/*
for(int i=1;i<=scc;++i)
syno[i]=(word){500000+5,5000000+5};
*/
for(int i=;i<tot;++i){
int u=edges[i].from,v=edges[i].to;
if(Belong[u]!=Belong[v]){
G[Belong[u]].push_back(Belong[v]);
}
} /*
for(int i=1;i<=TOT;++i){
int ind=Belong[i];
if(syno[ind].vow > voc[i].vow)
{
syno[ind].vow= voc[i].vow;
syno[ind].len= voc[i].len;
}
else if(syno[ind].vow == voc[i].len)
syno[ind].len= min(syno[ind].len,voc[i].len);
}
*/
ll X=,Y=;
//for(int i=1;i<=scc;++i)
// cout<<"scc "<<i<<" : "<<syno[i].vow<<" and "<<syno[i].len<<endl; for(int i=;i<=scc;++i){
int ans1,ans2;
ans1=syno[i].vow;
ans2=syno[i].len;
DFS(i);
} for(int i=;i<=n;++i){
int ans1, ans2;
ans1=syno[Belong[dict[ori[i]]]].vow;
ans2=syno[Belong[dict[ori[i]]]].len;
//DFS(Belong[i],ans1,ans2);
//cout<<Belong[i]<<endl;
X+=1ll*ans1;
Y+=1ll*ans2;
}
cout<<X<<' '<<Y<<endl;
return ;
}
后来看到别人代码,发现可以定义一个类,把优解与劣解的比较重载为<
#include <bits/stdc++.h>
using namespace std; #define IsVow(x) ((x)=='a'||(x)=='e'||(x)=='i'||(x)=='o'||(x)=='u')
typedef long long ll;
const int maxn=3e5+;
struct word{
ll vow;
ll len;
word(){}
word(ll _v,ll _l):vow(_v),len(_l){}
bool operator< (const word & tmp)const{
if(vow==tmp.vow) return len<tmp.len;
return vow<tmp.vow;
}
word operator+ (const word& tmp)const{
return word(vow+tmp.vow,len+tmp.len);
}
};
word voc[maxn],syno[maxn]; struct Edge{
int from;
int to;
int nxt;
}edges[maxn];
map<string ,int > dict;
string strcash[+];
int head[maxn],tot; int DFN[maxn],LOW[maxn],STK[maxn],BLG[maxn],top=,scc=,dfs_no=;
bool InSTK[maxn];
vector< vector< int > > G(maxn+,vector<int>() );
int vis[maxn];
void Tarjan(int u){
LOW[u]=DFN[u]=++dfs_no;
STK[top++]=u;
InSTK[u]=true;
for(int i=head[u];i!=-;i=edges[i].nxt){
int v=edges[i].to;
if(!DFN[v]){
Tarjan(v);
LOW[u]=min(LOW[u],LOW[v]);
}
else if(InSTK[v])
LOW[u]=min(LOW[u],DFN[v]);
}
if(DFN[u]==LOW[u]){
int v;
scc++;
syno[scc]=word(+,+);
do{
v=STK[--top];
InSTK[v]=false;
BLG[v]=scc;
if(voc[v]<syno[scc])
syno[scc]=voc[v];
}while(u!=v);
}
} word make_word(string X){
ll _l=1ll*X.length();
ll _v=;
for(auto const & i:X){
if(IsVow(i)) _v++;
}
return word(_v,_l);
} void AddEdge(int u,int v){
edges[tot].from=u;
edges[tot].to=v;
edges[tot].nxt=head[u];
head[u]=tot++;
} void DFS(int u){
if(vis[u]) return;
vis[u]=true;
for(auto v:G[u]){
DFS(v);
if(syno[v]<syno[u]) syno[u]=syno[v];
}
} int main(){
ios::sync_with_stdio(false);cin.tie();
int _n,_k;
int vtx_no=;
cin>>_n;
for(int i=;i<_n;++i){
string tmp;cin>>tmp;
strcash[i]=tmp;
if(dict.count(tmp)==){
dict[tmp]=++vtx_no;
voc[vtx_no]=make_word(tmp);
}
}
cin>>_k;
memset(head,-,sizeof(head));
tot=;
for(int i=;i<_k;++i){
string frm,to;cin>>frm>>to;
if(dict.count(frm)==){
dict[frm]=++vtx_no;
voc[vtx_no]=make_word(frm);
}
if(dict.count(to)==){
dict[to]=++vtx_no;
voc[vtx_no]=make_word(to);
}
AddEdge(dict[frm],dict[to]);
} top=,scc=,dfs_no=;
for(int i=;i<=vtx_no;++i){
if(!DFN[i]) Tarjan(i);
}
for(int i=;i<tot;++i){
int u=edges[i].from,v=edges[i].to;
u=BLG[u];
v=BLG[v];
if(u!=v) G[u].push_back(v);
}
//for(int i=1;i<=vtx_no;++i) cout<<"voc "<<i<<" : "<<voc[i].vow<<" , "<<voc[i].len<<endl;
//for(int i=1;i<=vtx_no;++i) cout<<strcash[i]<<":"<<i<<" belongs to "<<BLG[i]<<endl;
memset(vis,false,sizeof(vis));
//for(int i=1;i<=scc;++i) cout<<syno[i].vow<<" "<<syno[i].len<<endl;
for(int i=;i<=scc;++i){
DFS(i);
}
//puts("after DFS:");for(int i=1;i<=scc;++i) cout<<syno[i].vow<<" "<<syno[i].len<<endl;
ll __X=,__Y=;
for(int i=;i<_n;++i){
int ob=BLG[dict[strcash[i]]];
__X+=syno[ob].vow;
__Y+=syno[ob].len;
}
cout<<__X<<" "<<__Y<<endl;
return ;
}
转念一想,所谓点之间的优劣比较不就是先比元音数,元音数同则比长度吗?这不就是 STL里pair 的比较吗!?要啥结构体,要啥重载< !?
在算导上求scc那部分,有一个定理,有向图G=<V,E>的强连通分量与其逆图~G=<V,~E>的强连通分量是重合的。(逆图,,,沉思,,,
想一想,如果不缩点,在求解搜点时从每个点搜到其最优解点的路径是一条单向路径,同一个scc内的点能到的最优解是相同的,不同的scc也可能到相同的优解,它们的终点是相同的,终点相同我们可以做逆图!!!也就是从这个解按反向搜到可以到达这个解的所有点。
在建图时,有向边方向取逆,搜索时从最优的点(用间接排序)开始搜,如此只用一遍DFS。
#include <bits/stdc++.h>
using namespace std; #define IsVow(i) ((i)=='a'||(i)=='e'||(i)=='i'||(i)=='o'||(i)=='u')
typedef long long ll; string strcash[+]; map<string ,int > dict;
pair<ll,ll > word[+];
int word_no=; struct Edge{
int to;
int nxt;
}edges[+];
int head[+],tot; int id[+];
bool vis[+]; pair<ll,ll> make_word(string X){
ll len=X.length();
ll cnt=;
for(const auto & i:X){
if(IsVow(i)) cnt++;
}
return make_pair(cnt,len);
} void AddVtx(string X){
if(dict.count(X)==){
dict[X]=++word_no;
word[word_no]=make_word(X);
}
} void AddEdge(int u,int v){
edges[tot].to=v;
edges[tot].nxt=head[u];
head[u]=tot++;
} bool cmp(int i,int j){
return word[i]<word[j];
} void DFS(int u){
if(vis[u]) return;
vis[u]=true;
for(int i=head[u];i!=-;i=edges[i].nxt){
int v=edges[i].to;
//cout<<u<<"->"<<v<<endl;
if(!vis[v]){
word[v]=word[u];
//cout<<"DFS "<<v<<endl;
DFS(v);
}
}
} int main(){
ios::sync_with_stdio(false);cin.tie(); memset(head,-,sizeof(head));
tot=; int n,k;
cin>>n;
for(int i=;i<n;++i){
cin>>strcash[i];
AddVtx(strcash[i]);
}
cin>>k;
for(int i=;i<k;++i){
string f,t;cin>>f>>t;
AddVtx(f);
AddVtx(t);
AddEdge(dict[t],dict[f]);// ~G
} for(int i=;i<=word_no;++i)
id[i]=i;
sort(id+,id++word_no,cmp);
memset(vis,false,sizeof(vis));
for(int i=;i<=word_no;++i){
DFS(id[i]);
} ll X=,Y=;
for(int i=;i<n;++i){
int _no=dict[strcash[i]];
X+=word[_no].first;
Y+=word[_no].second;
}
cout<<X<<" "<<Y<<endl;
return ;
}
H-Modify Minieye杯第十五届华中科技大学程序设计邀请赛现场赛的更多相关文章
- Minieye杯第十五届华中科技大学程序设计邀请赛现场同步赛 I Matrix Again
Minieye杯第十五届华中科技大学程序设计邀请赛现场同步赛 I Matrix Again https://ac.nowcoder.com/acm/contest/700/I 时间限制:C/C++ 1 ...
- Minieye杯第十五届华中科技大学程序设计邀请赛网络赛D Grid(简单构造)
链接:https://ac.nowcoder.com/acm/contest/560/D来源:牛客网 题目描述 Give you a rectangular gird which is h cells ...
- Minieye杯第十五届华中科技大学程序设计邀请赛网络赛 部分题目
链接:https://pan.baidu.com/s/12gSzPHEgSNbT5Dl2QqDNpA 提取码:fw39 复制这段内容后打开百度网盘手机App,操作更方便哦 D Grid #inc ...
- 第十五届北京师范大学程序设计竞赛现场决赛题解&源码(A.思维,C,模拟,水,坑,E,几何,思维,K,字符串处理)
#include <bits/stdc++.h> using namespace std; int main() { int T,n,a,b; while(cin>>T) { ...
- 第十四届华中科技大学程序设计竞赛决赛同步赛 A - Beauty of Trees
A - Beauty of Trees 题意: 链接:https://www.nowcoder.com/acm/contest/119/A来源:牛客网 Beauty of Trees 时间限制:C/C ...
- 第十四届华中科技大学程序设计竞赛 K--Walking in the Forest
链接:https://www.nowcoder.com/acm/contest/106/K来源:牛客网 题目描述 It’s universally acknowledged that there’re ...
- 第十四届华中科技大学程序设计竞赛--J Various Tree
链接:https://www.nowcoder.com/acm/contest/106/J来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536 ...
- 第十四届华中科技大学程序设计竞赛决赛同步赛 F Beautiful Land(01背包,背包体积超大时)
链接:https://www.nowcoder.com/acm/contest/119/F来源:牛客网 Beautiful Land 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 1 ...
- 第十四届华中科技大学程序设计竞赛 K Walking in the Forest【二分答案/最小化最大值】
链接:https://www.nowcoder.com/acm/contest/106/K 来源:牛客网 题目描述 It's universally acknowledged that there'r ...
随机推荐
- IDEA右侧 Maven oracle依赖包有红色波浪线
1\下载 ojdbc14-10.2.0.4.0.jar http://www.java2s.com/Code/Jar/o/Downloadojdbc14102040jar.htm 2.将ojdbc14 ...
- ASP.NET Core 1.1版本之Hello word
1.下载ASP.NET Core 1.1版本,并且安装. 2.新建一个工作文件夹,本文以WebApiFrame名称为例建立一个新的文件夹: mk WebApiFrame 3.启动命令行,在命令行中进入 ...
- Springboot jar包外指定配置文件及原理
解决方案: 修改maven的pom.xml文件 不拷贝资源文件 <resources> <resource> <directory>src/main/resourc ...
- 游戏AI
玩游戏太累了,我或许可以写一个机器人帮我玩游戏发QQ发空间啥的
- java+Selenium+TestNg搭建自动化测试架构(3)实现POM(page+Object+modal)
1.Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高测试用例 ...
- js关闭浏览器
不存在的 告诉策划:不好意思,这个需求实现不了. 旧版本浏览器有些支持window.close()方法,目前主流浏览器都不支持,就算让你 ...
- 特殊字符的过滤,防止xss攻击
概念 XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允 ...
- 【python】Django自定义模板函数
参考:https://blog.csdn.net/wenyuanhai/article/details/73656761 注意: 1.自定义模板函数的路径必须为APP的templatetags下:ap ...
- Awvs、Snort的下载安装
学渗透测试是我对自己的奖赏. 这是Awvs环境的搭建. 推荐链接:https://www.cnblogs.com/show2008/p/10371461.html 这是Snort环境搭建. 推荐链接: ...
- 关联tomcat源代码
1.进入tomcat官网下载对应版本源代码文件 2. 3..ctrl+鼠标左键 点击Cookie对象 4. 5.