【CF718E】Matvey's Birthday

题意:给你一个长度为n的,由前8个小写字母组成的字符串s。构建一张n个点的无向图:点i和点j之间有一条长度为1的边当且仅当:|i-j|=1或$s_i=s_j$,求这个图的直径,及直径条数。

$n\le 10^5$

题解:首先有一个比较关键的性质:原图任意两点间的最短路不超过2*8-1。证明显然,因为每个字符在最短路上最多出现2次。

我们先预处理一些东西:f[i][a]表示从i走到任意一个$s_j=a$的点j的最短路,g[a][b]表示从任意一个$s_i=a$的i走到$s_j=b$的j的最短路。转移时可以采用BFS,这里不详细描述。

然后我们枚举i,试图在前面找到距离i最远的点j。点i到点j的距离不难表示成:$min\{i-j,f[i][c]+f[j][c]+1\}$。所以我们可以先枚举i前面的2*8-1个字符,暴力统计答案,然后考虑如何求f[i][c]+f[j][c]+1的最小值。

有一个非常神奇的发现是:f[i][a]的取值一定是g[s[i]][a]或g[s[i]][a]+1,也就意味着我们对于每个i,都可以用一个二进制状态S表示它,其中S的第j位为1当且仅当f[i][a]=g[s[i]][a]+1。接着我们可以预处理出任意两个状态合并能得到的最小值,用v[a][b][S][T]表示,其意义为一个颜色为a,状态为S和一个颜色为b,状态为T的点合并时能得到的最小结果。然后在枚举i时我们可以枚举之前出现过的所有状态,直接调用最小值即可。

这个大概可以叫做DP套DP了吧~

时间复杂度:$O(n\alpha+\alpha^32^{2\alpha}+n\alpha2^{\alpha})$。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int maxn=100010;
typedef long long ll;
int n,ans;
ll sum;
char str[maxn];
int f[maxn][10],g[10][10],s[maxn],vis[maxn],dp[8][260],v[8][8][260][260],state[maxn];
vector<int> p[10];
vector<int>::iterator it;
queue<int> q;
int main()
{scanf("%d%s",&n,str);int i,j,u,a,b,c;for(i=1;i<=n;i++)    s[i]=str[i-1]-'a',p[s[i]].push_back(i);memset(f,0x3f,sizeof(f)),memset(g,0x3f,sizeof(g));for(i=0;i<8;i++){g[i][i]=0,vis[n+i+1]=1;memset(vis,0,sizeof(vis));for(it=p[i].begin();it!=p[i].end();it++)    q.push(*it),f[*it][i]=0,vis[*it]=1;while(!q.empty()){u=q.front(),q.pop();if(u!=1&&!vis[u-1])    q.push(u-1),vis[u-1]=1,f[u-1][i]=f[u][i]+1;if(u!=n&&!vis[u+1]) q.push(u+1),vis[u+1]=1,f[u+1][i]=f[u][i]+1;if(!vis[n+s[u]+1]){vis[n+s[u]+1]=1,g[s[u]][i]=f[u][i];for(it=p[s[u]].begin();it!=p[s[u]].end();it++) if(!vis[*it])q.push(*it),f[*it][i]=f[u][i]+1,vis[*it]=1;}}}memset(v,0x3f,sizeof(v));for(a=0;a<8;a++)   for(b=0;b<=a;b++){for(i=0;i<256;i++)   for(j=0;j<256;j++){for(c=0;c<8;c++) v[a][b][i][j]=min(v[a][b][i][j],g[a][c]+g[b][c]+((i>>c)&1)+((j>>c)&1)+1);v[b][a][j][i]=v[a][b][i][j];}}for(i=1;i<=n;i++){for(j=max(1,i-15);j<i;j++){int tmp=i-j;for(c=0;c<8;c++)  tmp=min(tmp,f[i][c]+f[j][c]+1);if(ans<tmp)    ans=tmp,sum=0;if(ans==tmp)  sum++;}for(a=0;a<8;a++) state[i]|=(f[i][a]-g[s[i]][a])<<a;for(a=0;a<8;a++) for(j=0;j<256;j++)    if(dp[a][j]){int tmp=v[a][s[i]][j][state[i]];if(ans<tmp)    ans=tmp,sum=0;if(ans==tmp)  sum+=dp[a][j];}if(i>15)    dp[s[i-15]][state[i-15]]++;}printf("%d %lld\n",ans,sum);return 0;
}//16 aaaaaaaaaaaaaaaa 17 aaaaaaaaaaaaaaaaa

转载于:https://www.cnblogs.com/CQzhangyu/p/8503958.html

【CF718E】Matvey's Birthday BFS+动态规划相关推荐

  1. CF718E Matvey‘s Birthday(状压、bfs、暴力、分类讨论)

    解析 比较复杂的一道题 看数据范围,我们肯定要从种类很少的颜色入手 因为第二种加边方式和颜色密切相关 所以设计disi,kdis_{i,k}disi,k​表示 i 号节点到颜色为 k 的节点的最小步数 ...

  2. [Leetcode][第97题][JAVA][交错字符串][BFS][动态规划]

    [问题描述][中等] [解答思路] 1. 动态规划 第 1 步:设计状态 f(i,j) 表示 s 1的前 i个元素和 s2 的前 j个元素是否能交错组成 s3的前 i + j 个元素 第 2 步:状态 ...

  3. [Leedcode][JAVA][第22题括号生成][DFS][BFS][动态规划]

    [问题描述]22. 括号生成 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合. 示例:输入:n = 3 输出:["((()))",&q ...

  4. 【算法题目】DFS BFS 动态规划 零钱兑换 Python

    322. 零钱兑换 给你一个整数数组 coins ,表示不同面额的硬币:以及一个整数 amount ,表示总金额.计算并返回可以凑成总金额所需的 最少的硬币个数 .如果没有任何一种硬币组合能组成总金额 ...

  5. HihoCoder - 1828 Saving Tang Monk II(bfs+动态规划/bfs+优先队列)

    题目链接:点击查看 题目大意:孙悟空要走迷宫去救唐僧,给出n和m约束迷宫大小: 迷宫中: S代表起点 T代表终点 B代表氧气区,经过可以获得一罐氧气,最多储存5罐氧气 #代表毒气区,经过需要花费2个时 ...

  6. HDU - 4784 Dinner Coming Soon(bfs+动态规划+优先队列)

    题目链接:点击查看 题目大意:有n个点,m条边,一个人要在时间T内从1走到n,并在途中进行交易,获得尽可能多的钱.这个人身上最多能带B包盐,每到一个地方都需要交纳一定的钱数,并且经过一定的时间才能通过 ...

  7. [Codeforces Round #373 DIV1E (CF718E)] Matvey's Birthday

    题意 给定一个字符串,字符集大小为8 将每个位置当做一个点,相邻位置有长度为1的连边,任意相同字母的位置之间有长度为1的连边.求图的直径和直径的长度. n≤105n\le 10^5 题解 求图的直径需 ...

  8. Codeforces 718E Matvey's Birthday bfs

    题意 给一个长度为n的字符串s,字符集大小为m. 再建立一张n个点的图,其中串中第i个字符就对应图中第i个点. 对这张图连这样两种边: 若对于i,j,满足|i-j|<=1,在点i和点j之间连双向 ...

  9. fifo算法模拟_我是怎样学习算法的?(V1.0)

    我相信很多人都是因为找工作才去看数据结构与算法,我自己也是出于这个目的.我自己在学习数据结构和算法上走了很多弯路,原因就是没有系统地的去学习.看了很多书,刷了很多题,浪费了不少时间,所以希望看到这篇文 ...

最新文章

  1. 将Eclipse代码导入到Android Studio的两种方式
  2. 泛微对协同管理的定义
  3. UVA 644 - Immediate Decodability
  4. 保存一个 Python 对象,之后使用时直接读取
  5. 腾讯下一步:关注通用AI,加大投入产业互联网,推出医疗新品AI显微镜
  6. Android软件盘(EditText)的搜索功能
  7. 转:Android View.post(Runnable )
  8. 使用VIsio绘制E-R图
  9. 面向公交营运管理的车路协同应用场景研究
  10. wine装通达信_linux下安装虚拟机,完美在linux系统下运行通达信软件
  11. FastStone Capture:Windows系统下小巧好用的宝藏电脑截图软件
  12. Google Code Jam 全球编程挑战赛来袭,报名倒计时!
  13. 微信小游戏实战--cocos creator实现wordle游戏(二)
  14. C语言实现16进制到2进制的转换
  15. 2022-2028年中国沉香产业竞争现状及投资前景分析报告
  16. 应急响应之windows进程排查
  17. jboot_jboot这些框架有意义吗
  18. C++ strcpy函数的使用
  19. 微信公众号网页授权登录完整步骤版学不会你打我....
  20. 感恩美文:生命中总有一些人值得感恩

热门文章

  1. 嵌入式 使用mp4v2将H264+AAC合成mp4文件
  2. Hive数据去重、多变一与一变多等实现
  3. np.c_ 对比 np.r_
  4. 全国22家奶粉企业69批次产品检出三聚氰胺
  5. ARPANET的设计思想 (分组交换)
  6. python打印2020某月的日历_教你用Python打印2020年日历
  7. SODA10M 数据集下载记录
  8. 【已解决】Chrome 出现Your Connection is not private 问题
  9. Flex中Tree的用法备忘(增删改查节点)
  10. RL论文阅读20 - MF类算法总结(VPG, TROP, PPO, DDPG, TD3, SAC)