题目大意&链接:

  http://codeforces.com/problemset/problem/718/E

  给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s。两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j]。求这个无向图的直径,以及直径数量。

题解:

   命题1:任意位置之间距离不会大于15。

  证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多为15。

  然后我们对于每个节点,需要计算出其与其他节点距离,当然为了不重复,只需考虑pos小于当前节点的位置。此时我们分为两种情况:

  1.|i-j|<=15;

  2.|i-j|>15。

  对于第一种我们是取|i-j|与i先到达一种字母,j也到达这种字母距离和取较小值。所以我们设

  $F[i][c]$表示i节点到达c这种字母的最小距离。即i到j的距离为:$min(|i-j|,F[i][c]+1+F[j][c])$。

  命题2:i与j到达的同一种字母的位置如果相同,一定不是最优解。

  证明:假设到达同一个位置,那么只可能是通过这个位置的左右两个节点。那么,对于到达左右这两个节点如果其路径之间不存在相同的字母,那么其距离和|i-j|相同,如果存在相同字母,则一定比当前方式短。综上所述,到达同一位置一定不是最短路。

  对于第二种,我们由命题1可知,其距离不会大于15。我们再来看一个命题:

  命题3:设$dis[c1][c2]$表示c1字母到达c2字母的最小距离,那么我们有,若$s[i]==c1$,则$dis[c1][c2]<=F[i][c2]<=dis[c1][c2]+1$。

  证明:这个……显然吧?

  我们此时考虑对于第二种情况下的j,|i-j|一定不是最短的,所以一定是从$F[i][c]+1+F[j][c]$中选取最小值,那么由命题3可知,我们并不需要其确切位置,仅需知道$F[i][c]$与$dis[ci][c]$之间的关系,然后我们可以用一个二进制数$mark[j]$来表示其与$dis[cj][c]$之间的关系,然后我们把关系相同(即mark[j]相同)的j统计其数量,然后再求一下此时i与某一种mark之间的最短路即可。

代码:

  

 #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=;
int n,f[N][],dis[][];
char s[N];
int q[N],d[N];
int mark[N];
int c[N][<<];
inline void bfs(int c){
int l=,r=;
for(int i=;i<=n;i++)if(s[i]-'a'==c){
q[r++]=i,d[i]=;
}else d[i]=-;
bool vis[]={};
vis[c]=true;
while(l<r){
int now=q[l++];
if(!vis[s[now]-'a']){
vis[s[now]-'a']=true;
for(int i=;i<=n;i++)
if(s[i]==s[now]&&d[i]==-){
d[i]=d[now]+;
q[r++]=i;
}
}
if(now>&&d[now-]==-) q[r++]=now-,d[now-]=d[now]+;
if(now<n&&d[now+]==-) q[r++]=now+,d[now+]=d[now]+;
}
for(int i=;i<=n;i++)
if(d[i]!=-)f[i][c]=d[i];
}
int main(){
// freopen("1.out","w",stdout);
scanf("%d",&n);
scanf("%s",s+);
memset(f,0x3f,sizeof(f));
for(int i=;i<;i++)
bfs(i);
memset(dis,0x3f,sizeof(dis));
for(int i=;i<=n;i++)
for(int j=;j<;j++)
dis[s[i]-'a'][j]=min(dis[s[i]-'a'][j],f[i][j]);
for(int i=;i<=n;i++) for(int j=;j<;j++)
if(f[i][j]>dis[s[i]-'a'][j]) mark[i]|=<<j;
// for(int i=1;i<=n;i++)
// printf("mark[%d]=%d\n",i,mark[i]);
int ans=;
long long cnt=;
for(int i=;i<=n;i++){
for(int j=max(i-,);j<i;j++){
int now=i-j;
for(int k=;k<;k++)
now=min(now,f[j][k]++f[i][k]);
if(now==ans) cnt++;
if(now>ans) ans=now,cnt=;
}
int t=i-;
if(t>=) c[s[t]-'a'][mark[t]]++;
for(int j=;j<;j++) for(int k=;k<;k++)
if(c[j][k]){
int now=0x7fffffff;
for(int l=;l<;l++){
now=min(now,dis[j][l]++f[i][l]+((k&(<<l))>>l));
//printf("%d\n",(k&(1<<l))>>l);
}
if(now==ans) cnt+=c[j][k];
if(now>ans) ans=now,cnt=c[j][k];
}
}
printf("%d %lld\n",ans,cnt);
}

【codeforces 718E】E. Matvey's Birthday的更多相关文章

  1. 【codeforces 415D】Mashmokh and ACM(普通dp)

    [codeforces 415D]Mashmokh and ACM 题意:美丽数列定义:对于数列中的每一个i都满足:arr[i+1]%arr[i]==0 输入n,k(1<=n,k<=200 ...

  2. 【codeforces 707E】Garlands

    [题目链接]:http://codeforces.com/contest/707/problem/E [题意] 给你一个n*m的方阵; 里面有k个联通块; 这k个联通块,每个连通块里面都是灯; 给你q ...

  3. 【codeforces 707C】Pythagorean Triples

    [题目链接]:http://codeforces.com/contest/707/problem/C [题意] 给你一个数字n; 问你这个数字是不是某个三角形的一条边; 如果是让你输出另外两条边的大小 ...

  4. 【codeforces 709D】Recover the String

    [题目链接]:http://codeforces.com/problemset/problem/709/D [题意] 给你一个序列; 给出01子列和10子列和00子列以及11子列的个数; 然后让你输出 ...

  5. 【codeforces 709B】Checkpoints

    [题目链接]:http://codeforces.com/contest/709/problem/B [题意] 让你从起点开始走过n-1个点(至少n-1个) 问你最少走多远; [题解] 肯定不多走啊; ...

  6. 【codeforces 709C】Letters Cyclic Shift

    [题目链接]:http://codeforces.com/contest/709/problem/C [题意] 让你改变一个字符串的子集(连续的一段); ->这一段的每个字符的字母都变成之前的一 ...

  7. 【Codeforces 429D】 Tricky Function

    [题目链接] http://codeforces.com/problemset/problem/429/D [算法] 令Si = A1 + A2 + ... + Ai(A的前缀和) 则g(i,j) = ...

  8. 【Codeforces 670C】 Cinema

    [题目链接] http://codeforces.com/contest/670/problem/C [算法] 离散化 [代码] #include<bits/stdc++.h> using ...

  9. 【codeforces 515D】Drazil and Tiles

    [题目链接]:http://codeforces.com/contest/515/problem/D [题意] 给你一个n*m的格子; 然后让你用1*2的长方形去填格子的空缺; 如果有填满的方案且方案 ...

随机推荐

  1. JVM学习--(一)基本原理

    前言 JVM一直是java知识里面进阶阶段的重要部分,如果希望在java领域研究的更深入,则JVM则是如论如何也避开不了的话题,本系列试图通过简洁易读的方式,讲解JVM必要的知识点. 运行流程 我们都 ...

  2. javaScript(2)---简单使用

    javaScript(2)---简单使用 学习要点: 1.创建一张HTML页面 2.<Script>标签解析 3.JS代码嵌入的一些问题 一.创建一张HTML页面 <!DOCTYPE ...

  3. Oracle删除重复行

    Oracle删除重复行 分类: ORACLE2010-12-12 17:10 423人阅读 评论(0) 收藏 举报 oracletabledeleteintegerinsert.net 查询及删除重复 ...

  4. 关于Python的那些话

    1.第一个选择:版本2还是3,我选择2,保守谨慎,3的成熟周期会很长2.三种基本的文本操作:     2.1.解析数据并将数据反序列化到程序的数据结构中     2.2.将数据以某种方式转化为另一种相 ...

  5. svn Server sent unexpected return value (403 Forbidden) in response to CHECKOUT

    今天,提交資料到公司svn服務器,但是一直提示 Server sent unexpected return value (403 Forbidden) in response to CHECKOUT ...

  6. linux(centos 7)学习之 ~目录下的文件anaconda-ks.cfg

    这个文件是记录安装系统的一些信息 #version=DEVEL # System authorization information auth --enableshadow --passalgo=sh ...

  7. J2EE--常见面试题总结 -- (二)

    1 Spring拦截器的基本功能是什么? 拦截器是基于Java的反射机制的,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单 ...

  8. 自建Nuget服务器

    前言 [PS:原文手打,转载说明出处,博客园] java有Maven,.net有Nuget,概念就不一一阐述了,自己百度.下面直接进入正题 搭建Nuget服务器 作案工具 工具:vs2017,Nuge ...

  9. [Micropython]TPYBoard v10x NRF24L01无线通讯模块使用教程

    1.实验目的: •       学习使用NRF24L01无线通讯模块 2.所需原器件: •       TPYBoard v10X开发板两块 •       NRF24L01无线通讯模块两个 •    ...

  10. LeeCode数组第15题三数之和

    题目:三数之和 内容: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中 ...