Codeforces 718E - Matvey's Birthday(思维题)
首先注意到这个图的特殊性:我们对于所有 \(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(思维题)的更多相关文章
- 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 ...
- Codeforces 515C 题解(贪心+数论)(思维题)
题面 传送门:http://codeforces.com/problemset/problem/515/C Drazil is playing a math game with Varda. Let’ ...
- Codeforces 1188B - Count Pairs(思维题)
Codeforces 题面传送门 & 洛谷题面传送门 虽说是一个 D1B,但还是想了我足足 20min,所以还是写篇题解罢( 首先注意到这个式子里涉及两个参数,如果我们选择固定一个并动态维护另 ...
- Codeforces 1365G - Secure Password(思维题)
Codeforces 题面传送门 & 洛谷题面传送门 首先考虑一个询问 \(20\) 次的方案,考虑每一位,一遍询问求出下标的这一位上为 \(0\) 的位置上值的 bitwise or,再一遍 ...
- Codeforces 1129E - Legendary Tree(思维题)
Codeforces 题面传送门 & 洛谷题面传送门 考虑以 \(1\) 为根,记 \(siz_i\) 为 \(i\) 子树的大小,那么可以通过询问 \(S=\{2,3,\cdots,n\}, ...
- CodeForces - 427A (警察和罪犯 思维题)
Police Recruits Time Limit: 1000MS Memory Limit: 262144KB 64bit IO Format: %I64d & %I64u Sub ...
- codeforces 848B Rooter's Song 思维题
http://codeforces.com/problemset/problem/848/B 给定一个二维坐标系,点从横轴或纵轴垂直于发射的坐标轴射入(0,0)-(w,h)的矩形空间.给出点发射的坐标 ...
- Codeforces 729D Sea Battle(简单思维题)
http://codeforces.com/contest/738/problem/D https://www.cnblogs.com/flipped/p/6086615.html 原 题意:海战 ...
- @codeforces - 718E@ Matvey's Birthday
目录 @description@ @solution@ @accepted code@ @detail@ @description@ 给定一个长度为 n 的字符串 s,保证只包含前 8 个小写字母 ' ...
随机推荐
- spyglass DFT
SolvNet spyglass clock_11 内部 generated clocks 在shift mode 不被 testclock 控制. Fix View the Incremental ...
- 3.4 Common Principles 通用原则
3.4 Common Principles 通用原则 Before going into details, let's see some overall DDD principles; 在讨论细节之前 ...
- SharkCTF2021 fastcalc题记
web --> python脚本编写练习. 直接访问发现全是乱码: 看包发现Content-Type里面没有charset=utf-8. 于是用python访问一下,用.encoding='ut ...
- Python 语法错误 except Exception, e: ^ SyntaxError: invalid syntax
出这个问题是因为python2和python3 语法有些不同 python2 和 3 处理 except 子句的语法有点不同,需要注意: Python2 try: print ("hello ...
- 修改 openssh 版本号
1.查看 sshd 位置 #which sshd 2.查看 /usr/sbin/sshd(二进制文件) 内容 #strings /usr/sbin/sshd | grep nicai 3.修改版本号, ...
- # Host xx.xxx.x.xxx found: line 1 /root/.ssh/known_hosts updated. Original contents retained as /root/.ssh/known_hosts.old
一直可以ssh登录远程服务器,突然不行了. 原因:远程服务器最近打过安全补丁,安全标识已经更新. 清理本机的安全密匙即可 解决办法: #ssh-keygen -R "需要远程服务器ip地址& ...
- 【Go语言学习笔记】Go语言的基础语法
上一篇已经说了,Go的语法和C的很接近,直接看看异同即可. 变量 变量名还是一样,字母或下划线开头,区分大小写.不能是关键字. Go定义了int32和int64这种类型来显示声明大小,和C里面的sho ...
- RedHat 7.0 下 FTP 服务的安装,启动,配置,以及虚拟用户的建立
(注意! 区分shell命令和往配置文件里加的代码不同) 一:ftp服务的安装,启动和启用. 1:vim /etc/sysconfig/selinux 改为disabled后重启 ...
- Windows 常用配置
安装IIS服务器 在服务器管理器中,选择"角色"添加角色 进入添加角色向导,在安装界面,选择服务器角色为:" Web服务器(IIS) " 角色服务勾选:应用程序 ...
- Mysql教程:(三)运算符:数学运算符
运算符:数学运算符 mysql> select class,number,maths,maths+5 from score; mysql>select class,number,chine ...