Codeforces 题面传送门 & 洛谷题面传送门

首先注意到这个图的特殊性:我们对于所有 \(s_i=s_j\)​ 的 \((i,j)\)​ 之间都连了条边,而字符集大小顶多只有 \(8\)​,因此当 \(n\)​ 比较大时这张图肯定是相当稠密的,故我们猜测这个直径长度肯定也不会太长。事实的确如此,具体来说,对于图上任意两个点 \(i,j\)​,它们之间最短距离的长度肯定不会超过 \(15\)​,具体证明大概就对于每一对字母 \((x,y)\)​,如果存在某两个位置 \(i,i+1\) 满足 \(s_i=x,s_{i+1}=y\) 那么我们就在 \(x,y\) 之间连一条无向边。那么显然得到的大小为 \(s\text{中出现过的字符个数}\) 的图是连通图,故 \(\forall i,j\),\(s_i,s_j\) 在图上的距离不会超过 \(7\),而对于图上的一个大点(也就是每一种字母缩成的一个点),其包含的所有小点两两之间的最短距离恰好为 \(1\),也就是说,对于我们缩点后形成的图,我们假设我们找到了一条路径 \(v_1\to v_2\to\cdots\to v_k\),那么我们最多只用花 \(1\) 的代价实现从 \(v_{k-1}\to v_k\) 这条边到达 \(v_k\to v_{k+1}\) 这条边。因此这个最短距离的上界就是 \(8+7=15\)。

接下来我们考虑探究一下两点 \(i,j\) 之间的最短路是什么。不妨假设 \(i<j\),那么从 \(i\) 到达 \(j\) 有两种选择,要么一直往右走,步数 \(j-i\),要么经过某条连接两个不相邻的点的边,而这可以视作,选择某种字符 \(c\),然后从 \(i\) 走到某个字符为 \(c\) 的点,然后 \(j\) 也走到某个字符为 \(c\) 的点,然后再花费 \(1\) 的代价连接这两个字符为 \(c\) 的点,那么我们记 \(dis_{i,c}\) 表示 \(i\) 到达字符为 \(c\) 的点的最小代价。\(dis_{i,c}\) 可以通过用建虚点的技巧,也就是对于每个字符建一个虚点,然后对于所有字符为 \(c\) 的点,连一条该点到该字符对应的虚点,权值为 \(1\) 的边以及该字符对应的虚点到该点,权值为 \(0\) 的边,再使用多源 01bfs 在 \(\mathcal O(8n)\) 的时间内求出。这样我们即可在 \(\mathcal O(1)\) 的时间内计算两个点的最短距离,即 \(dis(i,j)=\min(j-i,dis_{j,k}+dis_{i,k}+1)\),这样暴力枚举是平方的,不过注意到一个性质,就是如果 \(j-i>15\),那么显然这个 \(\min\) 会取到后者,因此对于 \(j-i\le 15\) 我们考虑暴力枚举,\(j-i>15\) 的情况,注意到如果我们设 \(disc_{c1,c2}\) 为所有 \(s_i=c1\) 的点中 \(dis_{i,c2}\) 的最小值,那么必然有 \(dis_{i,c}-disc_{s_i,c}\in\{0,1\}\)。因此我们考虑在枚举的过程中将这个状态用一个 \(8\) 位二进制数记录下来,具体来说我们对于每个 \(i\) 记录一个 \(8\) 位二进制数 \(S\),\(S\) 的第 \(c\) 位为 \(1\) 表示 \(dis_{i,c}-disc_{s_i,c}=1\),否则 \(dis_{i,c}-disc_{s_i,c}=0\),然后我们在枚举的过程中开一个桶 \(cnt_{j,S}\) 表示前面有多少个 \(s_i=j\) 且 \(j\) 的状态为 \(S\),然后对于前面的答案就暴力对所有 \(j,S\) 批量处理答案即可。

时间复杂度 \(\mathcal O(8192·n)\),由于完全卡不满,可以通过此题。

const int MAXN=1e5;
const int MAXP=256;
const int INF=1061109567;
int n,cnt[MAXP+2][9];char s[MAXN+5];
int dis[MAXN+15][9],disc[9][9],res=0;ll resc=0;
void merge(int x,int y){
// printf("%d %d\n",x,y);
if(x>res) res=x,resc=y;
else if(x==res) resc+=y;
}
int main(){
scanf("%d%s",&n,s+1);
memset(dis,63,sizeof(dis));memset(disc,63,sizeof(disc));
for(int i=0;i<8;i++){
deque<int> q;
for(int j=1;j<=n;j++) if(s[j]-'a'==i) dis[j][i]=0,q.push_back(j);
while(!q.empty()){
int x=q.front();q.pop_front();
if(x<=n){
if(x-1>=1&&dis[x-1][i]==INF) dis[x-1][i]=dis[x][i]+1,q.push_back(x-1);
if(x+1<=n&&dis[x+1][i]==INF) dis[x+1][i]=dis[x][i]+1,q.push_back(x+1);
if(dis[s[x]-'a'+n+1][i]==INF) dis[s[x]-'a'+n+1][i]=dis[x][i]+1,q.push_back(s[x]-'a'+n+1);
} else {
for(int j=1;j<=n;j++) if(s[j]-'a'==x-n-1)
if(dis[j][i]>=dis[x][i]) dis[j][i]=dis[x][i],q.push_front(j);
}
} for(int j=1;j<=n;j++) chkmin(disc[s[j]-'a'][i],dis[j][i]);
// for(int j=1;j<=n;j++) printf("%d%c",dis[j][i]," \n"[j==n]);
}
// for(int i=0;i<8;i++) for(int j=0;j<8;j++)
// printf("%d%c",disc[i][j]," \n"[j==7]);
for(int i=1;i<=n;i++){
for(int j=max(1,i-15);j<=i;j++){
int mn=i-j;
for(int k=0;k<8;k++) chkmin(mn,dis[j][k]+dis[i][k]+1);
merge(mn,1);
} if(i-16>=1){
int msk=0;
for(int j=0;j<8;j++) msk|=(dis[i-16][j]-disc[s[i-16]-'a'][j])<<j;
cnt[msk][s[i-16]-'a']++;
} for(int j=0;j<MAXP;j++) for(int k=0;k<8;k++) if(cnt[j][k]){
int mn=INF;
for(int l=0;l<8;l++) chkmin(mn,dis[i][l]+disc[k][l]+(j>>l&1)+1);
merge(mn,cnt[j][k]);
}
} printf("%d %lld\n",res,resc);
return 0;
}

Codeforces 718E - Matvey's Birthday(思维题)的更多相关文章

  1. C. Nice Garland Codeforces Round #535 (Div. 3) 思维题

    C. Nice Garland time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  2. Codeforces 515C 题解(贪心+数论)(思维题)

    题面 传送门:http://codeforces.com/problemset/problem/515/C Drazil is playing a math game with Varda. Let’ ...

  3. Codeforces 1188B - Count Pairs(思维题)

    Codeforces 题面传送门 & 洛谷题面传送门 虽说是一个 D1B,但还是想了我足足 20min,所以还是写篇题解罢( 首先注意到这个式子里涉及两个参数,如果我们选择固定一个并动态维护另 ...

  4. Codeforces 1365G - Secure Password(思维题)

    Codeforces 题面传送门 & 洛谷题面传送门 首先考虑一个询问 \(20\) 次的方案,考虑每一位,一遍询问求出下标的这一位上为 \(0\) 的位置上值的 bitwise or,再一遍 ...

  5. Codeforces 1129E - Legendary Tree(思维题)

    Codeforces 题面传送门 & 洛谷题面传送门 考虑以 \(1\) 为根,记 \(siz_i\) 为 \(i\) 子树的大小,那么可以通过询问 \(S=\{2,3,\cdots,n\}, ...

  6. CodeForces - 427A (警察和罪犯 思维题)

    Police Recruits Time Limit: 1000MS   Memory Limit: 262144KB   64bit IO Format: %I64d & %I64u Sub ...

  7. codeforces 848B Rooter's Song 思维题

    http://codeforces.com/problemset/problem/848/B 给定一个二维坐标系,点从横轴或纵轴垂直于发射的坐标轴射入(0,0)-(w,h)的矩形空间.给出点发射的坐标 ...

  8. Codeforces 729D Sea Battle(简单思维题)

    http://codeforces.com/contest/738/problem/D https://www.cnblogs.com/flipped/p/6086615.html   原 题意:海战 ...

  9. @codeforces - 718E@ Matvey's Birthday

    目录 @description@ @solution@ @accepted code@ @detail@ @description@ 给定一个长度为 n 的字符串 s,保证只包含前 8 个小写字母 ' ...

随机推荐

  1. diff算法深入一下?

    文章转自豆皮范儿-diff算法深入一下 一.前言 有同学问:能否详细说一下 diff 算法. 简单说:diff 算法是一种优化手段,将前后两个模块进行差异化比较,修补(更新)差异的过程叫做 patch ...

  2. 远程设备管理opendx平台搭建-appium和adb的安装

    多年不见了,说起来也有3年了我又开始写博客了,这几年我还是没啥长进,还是干测试,但是测试行业的话,我已经成了一个测开了,也在搭建自己的测试网站 本系列文章讲述的是一个系列的第一部分,最终可以搭建一整套 ...

  3. programmercarl——数组——二分查找

    二分查找,在经过: 34--https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-arr ...

  4. UltraSoft Scrum Meeting 博客汇总

    一.Alpha阶段 UltraSoft - Alpha - Scrum Meeting 1 UltraSoft - Alpha - Scrum Meeting 2 UltraSoft - Alpha ...

  5. Noip模拟32(再度翻车) 2021.8.7

    T1 Smooth 很水的一道题...可是最傻    的是考场上居然没有想到用优先队列优化... 上来开题看到这个,最一开始想,这题能用模拟短除法,再一想太慢了,就想着优化 偏偏想到线性筛然后试别的素 ...

  6. js fetch异步请求使用详解

    目录 认识异步 fetch(url) response.json() 结合async和await 异常处理 post请求 认识异步 首先我们得明白请求是一个异步的过程. 因为请求需要时间向服务器发送请 ...

  7. Django 实现分页功能(django 2.2.7 python 3.7.5 )

    Django 自带名为 Paginator 的分页工具, 方便我们实现分页功能.本文就讲解如何使用 Paginator 实现分页功能. 一. Paginator Paginator 类的作用是将我们需 ...

  8. 你们不要再吵了! Java只有值传递..

    写在前边 上次聊到Java8新特性 lambda时,有小伙伴在评论区提及到了lambda对于局部变量的引用,补充着博客的时候,知识点一发散就有了这篇对于值传递还是引用传递的思考.关于这个问题为何会有如 ...

  9. .Net Core微服务——网关(2):ocelot集成consul

    有consul基础的都知道,consul可以发现新增的服务,剔除掉无效的服务,赋予应用自动伸缩的能力.而ocelot如果集成了consul,那ocelot也能拥有这些能力,还可以自主选择负载均衡策略, ...

  10. SpringCloud升级之路2020.0.x版-31. FeignClient 实现断路器以及线程隔离限流的思路

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在前面一节,我们实现了 FeignClient 粘合 resilience4j 的 Ret ...