首页 > 其他分享 >[AGC046D] Secret Passage 题解

[AGC046D] Secret Passage 题解

时间:2023-10-19 09:44:06浏览次数:42  
标签:后缀 题解 合法 int Secret Passage AGC046D

Secret Passage

稍微观察一下就能发现,任一时刻,我们剩下的东西必然是一段定死了的后缀,加上一些可以任意塞位置的 0 与 1。考虑任意一个由上述时刻生成的串,就会发现它与该后缀的最长公共子序列长度即为后缀长度,且还剩余一些 0 与 1。

于是考虑模拟最长公共子序列的过程。设 \(g_{i,j,k}\) 表示长度为 \(n-i+1\) 的后缀,所有与其 LCS 就是该后缀本身,且多余 \(j\) 个 0、\(k\) 个 1 的串数。为了不重复计数,我们强制 0 只能插在原后缀的 1 前面,1 只能插在原后缀的 0 前面。倒序转移即可。

并非所有 \((i,j,k)\) 都是合法的。我们还需要求出合法的状态。设 \(f_{i,j,k}\) 表示其是否合法。则,一个状态合法,当且仅当其通过一步 LCS 匹配能够到达另一个合法状态,或者其通过删除再插入操作能够到达另一个合法状态。两种方案分别转移即可。

时间复杂度 \(O(n^3)\)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
const int N=310; 
int n,res,g[N][N][N],h[N][N];
bool f[N][N][N];
char s[N];
signed main(){
    scanf("%s",s+1);
	n=strlen(s+1);
    f[0][0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=n;j>=0;j--){
			for(int k=n;k>=0;k--){
			    f[i][j][k]|=f[i-1][j][k];
			    if(s[i]=='0') f[i][j][k]|=f[i][j][k+1];
			    if(s[i]=='1') f[i][j][k]|=f[i][j+1][k];
			}
		}
        if(i>1){
			for(int j=0;j<=n;j++){
				for(int k=0;k<=n;k++){
					if((s[i-1]=='0'||s[i]=='0')&&j) f[i][j][k]|=f[i-2][j-1][k];
					if(s[i-1]=='0'&&s[i]=='0'&&j) f[i][j][k]|=f[i-1][j-1][k+1];
					if((s[i-1]=='1'||s[i]=='1')&&k) f[i][j][k]|=f[i-2][j][k-1];
					if(s[i-1]=='1'&&s[i]=='1'&&k) f[i][j][k]|=f[i-1][j+1][k-1];
				}
			}
		}
    }
    g[n][0][0]=1;
    for(int i=n;i;i--){
		for(int j=0;j<=n;j++){
			for(int k=0;k<=n;k++){
				(g[i-1][j][k]+=g[i][j][k])%=mod;
				if(s[i]=='0') (g[i][j][k+1]+=g[i][j][k])%=mod;
				if(s[i]=='1') (g[i][j+1][k]+=g[i][j][k])%=mod;
			}
		}
	}
    for(int i=0;i<=n;i++){
		for(int j=0;j<=n;j++){
			for(int k=0;k<=n;k++){
				if(f[i][j][k]) (res+=g[i][j][k])%=mod;
			}
		}
	}
    printf("%d",(res+mod-1)%mod);
    return 0;
}

标签:后缀,题解,合法,int,Secret,Passage,AGC046D
From: https://www.cnblogs.com/xuantianhao/p/17773986.html

相关文章

  • Atcoder Beginner Contest 324 G Generate Arrays 题解-Treap
    为了更好的阅读体验,请点击这里题目链接套上平衡树板子就能做的很快的题,然后因为是指针存树,因此交换只需要把序列大小较小的挨个拿出来插到相应的地方即可。复杂度\(O(N\log^2N)\)。但是一定要记住不可以直接使用std::swap交换包含带有指针的类的实例(如代码中的Treap类)!......
  • 精选题解汇总
    Part1比赛题解CF1873CF1203CF1234CF1249Part2难题题解P1124P6346P2198P7974P4814......
  • P1124 题解
    题目大意一个长度为\(n\)的字符串\(S\),进行以下操作。假设\(s\)为acbdef,每一次将首字母移至末尾,得到\(6\)个字符串:acbdefcbdefabdefacdefacbefacbdfacbde将每个字符串的首字母排序:acbdefbdefaccbdefadefacbefacbdfacbde每个字符串的末尾连在一起为fcab......
  • Linux 环境下(Ubuntu)webbench的安装问题解决与使用
    webbench最多可以模拟3万个并发连接去测试网站的负载能力。并发能力比较高,可以测试https及动态静态页面。适合中小型网站测试承受能力。原理:父进程fork若干个子进程,每个子进程在用户要求时间或默认的时间内对目标web循环发出实际访问请求,父子进程通过管道进行通信,子进程通过......
  • P6346 题解
    题目大意如果\(\texttt{Kevin}\)想和第\(i\)个人交朋友,要么需要认识\(a_i\)个人,要么付出\(b_i\)的代价,他让你使\(\texttt{Kevin}\)与所有的人交朋友。解题思路如果想水到\(15\)分,也就是所有\(b_i\)都等于\(1\)的情况,那我们可以直接排个序,然后遍历一下每一个人,......
  • P2198 题解
    解题思路激光塔一定在最后。\(f_{i,j}\)表示前\(i\)个位置放\(j\)(\(j\lei\))个放射塔,那么\(i-j\)个干扰塔的伤害。若第\(i\)个位置放放射塔:\(f_{i,j}=f_{i-1,j-1}+(j-1)\timesg\times[t+b\times(i-j)]\)若第\(i\)个位置放干扰塔,也就是\(j<i\):\(f_{i,j}=\max\{f_{i-......
  • P7974 题解
    解题思路首先可以确保每一次列的方向一定不会与\(s\)到\(t\)的方向相反。不妨设\(l=\min\{s,t\}\),\(r=\max\{s,t\}\)。对于每次移动,所花体力值如下:显然,从\(l\)到\(r\),一定要翻过\([l,r]\)间最高的一个,区间最大我们毫不犹豫地选择ST表,然后我们思考一下,令\(h_x=\m......
  • P4814 题解
    解题思路对于每条边\((u,v)\),权值为\(w\),假设存在一条经过这一条边的路径,其最短距离为\(a\)到\(u\)的最短路加上\(v\)到\(b\)的最短距离加上\(w\),若这个值都大于\(d\),则不可能关闭这条边。由于边权非负,所以可采用dijkstra来处理最短路。因为为有向边,所以可以再建......
  • C++常见入门题题解
    前言因为本人目前比较菜,所以给出的题解都是按照自己的学习进度来的,所以难度是一个循序渐进的过程,由于本人水平有限,望读者能够指出谬误,共同进步。回文数输出#include<bits/stdc++.h>//万能头usingnamespacestd;intmain(void){vector<int>font;//定义一个整型的向......
  • 题解 CF1651F【Tower Defense】
    题解CF1651F【TowerDefense】problem一个塔防游戏。一共有\(n\)个塔按\(1\simn\)的顺序排成一列,每座塔都有魔力容量\(c_i\)和魔力恢复速率\(r_i\)。对于一座塔\(i\),每过一秒它的魔力\(m_i\)会变为\(\min(m_i+r_i,c_i)\)。每座塔初始时满魔力。一共有\(q\)个......