【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

【CF718E】Matvey's Birthday BFS+动态规划的更多相关文章

  1. Prime Path素数筛与BFS动态规划

    埃拉托斯特尼筛法(sieve of Eratosthenes ) 是古希腊数学家埃拉托斯特尼发明的计算素数的方法.对于求解不大于n的所有素数,我们先找出sqrt(n)内的所有素数p1到pk,其中k = ...

  2. LeetCode入门指南 之 动态规划思想

    推荐学习labuladong大佬的动态规划系列文章:先弄明白什么是动态规划即可,不必一次看完.接着尝试自己做,没有思路了再回过头看相应的文章. 动态规划一般可以由 递归 + 备忘录 一步步转换而来,不 ...

  3. [题解+总结]NOIP2010-2015后四题汇总

    1.前言 正式开始的第一周的任务--把NOIP2010至NOIP2015的所有D1/2的T2/3写出暴力.共22题. 暴力顾名思义,用简单粗暴的方式解题,不以正常的思路思考.能够较好的保证正确性,但是 ...

  4. ACM知识点

    基础算法 高精 模拟 分治 贪心 排序 DFS 迭代加深搜索 BFS 双向BFS 动态规划 DAG上DP 树上DP 线性DP 图算法 最短路 FLYD DJATL BF 最大流 Dinic ISAP ...

  5. 百度AIG知识图谱部算法实习生面经(已拿offer)

    一面: 1.自我介绍 2.平时用什么编程语言比较多 python,另外学过C语言和JAVA 3.c语言里指针占多少内存 答成8位了,应该根据机器而言是16位或32位 4.python里的map函数,讲 ...

  6. NOIP2010-2015后四题汇总

    1.前言 正式开始的第一周的任务——把NOIP2010至NOIP2015的所有D1/2的T2/3写出暴力.共22题. 暴力顾名思义,用简单粗暴的方式解题,不以正常的思路思考.能够较好的保证正确性,但是 ...

  7. poj分类解题报告索引

    图论 图论解题报告索引 DFS poj1321 - 棋盘问题 poj1416 - Shredding Company poj2676 - Sudoku poj2488 - A Knight's Jou ...

  8. BZOJ4828 AHOI/HNOI2017大佬(动态规划+bfs)

    注意到怼大佬的操作至多只能进行两次.我们逐步简化问题. 首先令f[i][j]表示第i天结束后自信值为j时至多有多少天可以进行非防御操作(即恢复自信值之外的操作).这个dp非常显然.由于最终只需要保证存 ...

  9. Java实现 LeetCode 1162 地图分析(可以暴力或者动态规划的BFS)

    1162. 地图分析 你现在手里有一份大小为 N x N 的『地图』(网格) grid,上面的每个『区域』(单元格)都用 0 和 1 标记好了.其中 0 代表海洋,1 代表陆地,你知道距离陆地区域最远 ...

随机推荐

  1. ZooKeeper学习之-Zookeeper简单介绍(一)

    一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调技术.那么什么是分布式协调技术?那么我来告诉大家,其实分布式协调技术主要用来解决分布式环境当中多个进程之间的同 ...

  2. C语言之Bit-wise Operation和Logical Operation

    首先第一点:十六进制位运算和逻辑运算 都是先转化二进制,后输出结果(十六进制,二或十)Bit-Wise Operations (位运算)包括:& 按位与 | 按位或 ^ 按位异或 ~ 取反 & ...

  3. TensorFlow安装,升级,基本操作

    一. 安装 ubuntu 16 python 2.7 pip install tensorflow 测试安装完成效果: 查看tensorFlow版本python import tensorflow a ...

  4. BarTender表单的人性化设计—分组框

    BarTender 2016已经支持用户输入信息.从相同位置查询数据库和筛选数据记录,那就是数据输入表单了.这个功能相信迎合了很多用户的需求,主要作用体现在打印时数据输入. 对于表单的设计,不同的客户 ...

  5. 教你下载BarTender 2016

    BarTender是全球领先标签.条形码.RFID和证卡设计打印软件,功能强大,操作简单,具有很强的灵活性.目前,BarTender软件已更新至最新版BarTender 2016.BarTender ...

  6. varchar和nvarchar的区别 数据来证明

    如果一个数据是"N好"数据类型是varchar时: select len(vartest) from testselect datalength(vartest) from tex ...

  7. 输入控件tagsinput

    ​摘要: ​tagsinput是一款基于jQuery的插件.具有组织输入内容.校验.backspace删除等功能.当你在输入框输入结束按下enter键,tagsinput会将你输入的内容用标签封装,每 ...

  8. spring boot整合activemq消息中间件

    spring boot整合activemq消息中间件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi ...

  9. linux系统调用函数---12

    Linux应用编程学习笔记                                 周学伟 一.系统调用文件编程   1.文件打开函数 /*************************** ...

  10. Gibbs采样

    (学习这部分内容大约需要50分钟) 摘要 Gibbs采样是一种马尔科夫连蒙特卡洛(Markov Chain Monte Carlo, MCMC)算法, 其中每个随机变量从给定剩余变量的条件分布迭代地重 ...