题目大意&链接:

  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之间的最短路即可。

代码:

  

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 const int N=100100;
 6 int n,f[N][16],dis[20][20];
 7 char s[N];
 8 int q[N],d[N];
 9 int mark[N];
10 int c[N][1<<8];
11 inline void bfs(int c){
12     int l=0,r=0;
13     for(int i=1;i<=n;i++)if(s[i]-'a'==c){
14         q[r++]=i,d[i]=0;
15     }else   d[i]=-1;
16     bool vis[16]={0};
17     vis[c]=true;
18     while(l<r){
19         int now=q[l++];
20         if(!vis[s[now]-'a']){
21             vis[s[now]-'a']=true;
22             for(int i=1;i<=n;i++)
23                 if(s[i]==s[now]&&d[i]==-1){
24                     d[i]=d[now]+1;
25                     q[r++]=i;
26                 }
27         }
28         if(now>1&&d[now-1]==-1) q[r++]=now-1,d[now-1]=d[now]+1;
29         if(now<n&&d[now+1]==-1) q[r++]=now+1,d[now+1]=d[now]+1;
30     }
31     for(int i=1;i<=n;i++)
32         if(d[i]!=-1)f[i][c]=d[i];
33 }
34 int main(){
35    // freopen("1.out","w",stdout);
36     scanf("%d",&n);
37     scanf("%s",s+1);
38     memset(f,0x3f,sizeof(f));
39     for(int i=0;i<8;i++)
40         bfs(i);
41     memset(dis,0x3f,sizeof(dis));
42     for(int i=1;i<=n;i++)
43         for(int j=0;j<8;j++)
44             dis[s[i]-'a'][j]=min(dis[s[i]-'a'][j],f[i][j]);
45     for(int i=1;i<=n;i++)   for(int j=0;j<8;j++)
46         if(f[i][j]>dis[s[i]-'a'][j])    mark[i]|=1<<j;
47    // for(int i=1;i<=n;i++)
48    //     printf("mark[%d]=%d\n",i,mark[i]);
49     int ans=0;
50     long long cnt=0;
51     for(int i=1;i<=n;i++){
52         for(int j=max(i-15,1);j<i;j++){
53             int now=i-j;
54             for(int k=0;k<8;k++)
55                 now=min(now,f[j][k]+1+f[i][k]);
56             if(now==ans)    cnt++;
57             if(now>ans)     ans=now,cnt=1;
58         }
59         int t=i-16;
60         if(t>=1)    c[s[t]-'a'][mark[t]]++;
61         for(int j=0;j<8;j++)    for(int k=0;k<256;k++)
62             if(c[j][k]){
63                 int now=0x7fffffff;
64                 for(int l=0;l<8;l++){
65                     now=min(now,dis[j][l]+1+f[i][l]+((k&(1<<l))>>l));
66                    //printf("%d\n",(k&(1<<l))>>l);
67                 }
68                 if(now==ans)    cnt+=c[j][k];
69                 if(now>ans) ans=now,cnt=c[j][k];
70             }
71     }
72     printf("%d %lld\n",ans,cnt);
73 }

转载于:https://www.cnblogs.com/Troywar/p/7512460.html

【codeforces 718E】E. Matvey's Birthday相关推荐

  1. 【CodeForces - 144C】Anagram Search(尺取,滑窗问题,处理字符串计数)

    题干: A string t is called an anagram of the string s, if it is possible to rearrange letters in t so ...

  2. 【CodeForces - 574B】Bear and Three Musketeers (枚举边,思维,优秀暴力)

    题干: Do you know a story about the three musketeers? Anyway, you will learn about its origins now. Ri ...

  3. 【CodeForces - 608C】Chain Reaction (二分 或 dp ,思维)

    题干: 题目大意: 题意是在一条直线上坐落着不同位置的灯塔,每一个灯塔有自己的power level,当作是射程范围.现在从最右边的灯塔开始激发,如果左边的灯塔在这个灯塔的范围之内,那么将会被毁灭.否 ...

  4. 「一题多解」【CodeForces 85D】Sum of Medians(线段树 / 分块)

    题目链接 [CodeForces 85D]Sum of Medians 题目大意 实现一个setsetset,支持插入,删除,求∑a5k+3∑a5k+3\sum a_{5k+3}.注意,setsets ...

  5. 【CodeForces 997C】Sky Full of Stars(组合计数)

    题目链接:[CodeForces 997C]Sky Full of Stars 官方题解:Codeforces Round #493 - Editorial 题目大意:有一个n×nn×nn\times ...

  6. 【codeforces 812C】Sagheer and Nubian Market

    [题目链接]:http://codeforces.com/contest/812/problem/C [题意] 给你n个物品; 你可以选购k个物品;则 每个物品有一个基础价值; 然后还有一个附加价值; ...

  7. 【codeforces 508B】Anton and currency you all know

    [题目链接]:http://codeforces.com/contest/508/problem/B [题意] 给你一个奇数; 让你交换一次数字; 使得这个数字变成偶数; 要求偶数要最大; [题解] ...

  8. 【codeforces 711B】Chris and Magic Square

    [题目链接]:http://codeforces.com/contest/711/problem/B [题意] 让你在矩阵中一个空白的地方填上一个正数; 使得这个矩阵两个对角线上的和; 每一行的和,每 ...

  9. 【codeforces 807C】Success Rate

    [题目链接]:http://codeforces.com/contest/807/problem/C [题意] 给你4个数字 x y p q 要求让你求最小的非负整数b; 使得 (x+a)/(y+b) ...

最新文章

  1. 2、redis.conf基本配置项说明
  2. 算法 - 选择排序(C#)
  3. nb-iot简介【转】
  4. 【赠书】图表示学习+图神经网络:破解AI黑盒,揭示万物奥秘的钥匙!
  5. dockerfile php环境变量,docker - 在Dockerfile中,如何更新PATH环境变量?
  6. kali 安装volatility_volatility取证学习-linux
  7. 几种嵌入式RTOS的分析与比较
  8. 获取线程号 gettid()【原创】
  9. 解析复杂结构的json文件的时候,快速生成结构体--golang
  10. Asterisk 函数
  11. java多线程使用心得
  12. MYSQL数据库升级
  13. 深度学习软件开发环境搭建
  14. 机器学习之层次聚类(hierarchical clustering)
  15. 【luogu/字符串】多项式输出(所有情况一起处理)
  16. 梅花雪MzTreeView2.0 的checkbox完全攻略
  17. photoshop笔记
  18. android tag的使用方法,Android setTag方法的key问题解决办法
  19. Anaconda安装Jupyter Notebook及使用
  20. 小米5C解BL锁教程申请BootLoader解锁教程

热门文章

  1. 使用QT发送http/https的post请求并接收服务器reply
  2. 卡莱特led显示屏调试教程_卡莱特5A接收卡调屏步骤.doc
  3. C#EXCEL操作大全
  4. 福建厦门计算机春季高考考哪些学校,福建省2020年春季高考总分多少?春季高考本科院校有哪些?...
  5. Threejs系列--10游戏开发--沙漠赛车游戏【基础事件处理器】
  6. android 反调试 方案,【木马分析】使用高级反调试与反HOOK的安卓恶意ROOT软件的深度分析(一):NATIVE层的调试...
  7. 湖南省中小学教师计算机培训,隆回信技术应用能力提升工程2.0管理团队和培训团队在长沙开班...
  8. 高级语言及其语法描述
  9. 追逐日月,不苟于山川。
  10. html折叠新闻网页版本号,数字报纸HTML版本