首页 > 其他分享 >Gym 100543G Virus synthesis 题解

Gym 100543G Virus synthesis 题解

时间:2024-10-07 09:21:49浏览次数:7  
标签:sz return cur int 题解 Gym 100543G len fail

Solution

首先只考虑回文串的答案;我们重点考虑的是偶回文串

结论:对于偶回文串 \(u\),从其最长的长度小于等于他的一半的回文后缀,或其父亲转移过来,一定是最优的

证明:

设 \(u\) 的一个回文子串为 \(v\)(不是父亲),你要让 \(v\to u\) 的转移最优

首先 \(v\) 不能跨过 \(u\) 的中点,因为此时“从父亲转移过来”一定不会更劣

其次 \(v\) 不能位于 \(u\) 的中间(非前后缀),因为这种情况 \(u\) 的祖先已经考虑到了

证完了

于是转移即可;对于奇回文串,他只能从其父亲或 fail 转移而来,证明是类似的。

做完了。

Code

#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
typedef long long ll;
const int N = 1e5 + 10;
string s;
int n;

int cur, last, sz, len[N], fail[N], nxt[N][4], f[N], half[N];
void init() {
	while (sz >= 0) {
		len[sz] = fail[sz] = f[sz] = half[sz] = 0;
		rep(i, 0, 3) nxt[sz][i] = 0;
		--sz;
	}
	cur = last = 0, sz = 1, len[1] = -1, fail[0] = 1;
}
int getfail(int u, int i) {
	while (i - len[u] - 1 < 0 || s[i - len[u] - 1] != s[i]) u = fail[u];
	return u;
}
void Solve() {
	cin >> s, n = s.length(), init();
	int ans = 114514;
	auto Get = [&](char c) {
		if (c == 'A') return 0;
		if (c == 'G') return 1;
		if (c == 'T') return 2;
		if (c == 'C') return 3;
		return 0;
	};
	rep(i, 0, n - 1) {
		int p = getfail(last, i), ch = Get(s[i]);
		if (!nxt[p][ch]) {
			cur = ++sz;
			fail[cur] = nxt[getfail(fail[p], i)][ch];
			nxt[p][ch] = cur;
			len[cur] = len[p] + 2;
			if (len[cur] & 1) {
				f[cur] = min(f[p] + 2, f[fail[cur]] + len[cur] - len[fail[cur]]);
			} else {
				int q = getfail(half[p], i);
				while (len[q] + 2 > len[cur] / 2) q = getfail(fail[q], i);
				if (len[cur] > 2 && (q || s[i] == s[i - 1])) q = nxt[q][ch];
				else q = 0;
				half[cur] = q;
				if (p) {
					f[cur] = min(f[p] + 1, f[half[cur]] + len[cur] / 2 - len[half[cur]] + 1);
				} else {
					f[cur] = 2;
				}
			}
			ans = min(ans, n - len[cur] + f[cur]);
		}
		last = nxt[p][ch];
	}
	cout << ans << '\n';
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr);
	int t;
	cin >> t;
	while (t--) Solve();
	return 0;
}

标签:sz,return,cur,int,题解,Gym,100543G,len,fail
From: https://www.cnblogs.com/laijinyi/p/18449775

相关文章

  • LOJ 6041 事情的相似度 题解
    Statement先把串reverse,多次给\(l,r\),求\[\max_{l\lei<j\ler}\{\text{LCP}(i,j)\}\]Solution\(\text{sqrtlog}\sim\text{sqrt}\):莫队+线段树/树状数组/set,用SA做\(nm/\omega\):bitset乱搞\(\log^2\):SAM+LCT+BIT在parent树上,LCP等于LCA的......
  • P3332 K大数查询 题解
    Solution整体二分板子题vector太好写了111#include<bits/stdc++.h>usingnamespacestd;#definerep(i,j,k)for(inti=(j);i<=(k);++i)#definereo(i,j,k)for(inti=(j);i>=(k);--i)typedeflonglongll;constintN=50010;intn,m,ans[......
  • P4093 序列 题解
    Statement给出\(n\) 个数的序列\(\{a_i\}\),接下来\(m\)秒中每一秒会有一个数发生变化,然后恢复。问最长的子序列长度,使得任意时刻这个子序列不下降。\(n\le10^5\)Solution设\(b_i\)为\(i\)最小能变成的数,\(c_i\)为\(i\)最大能变成的数\[f(i)=\max_{j<i\landc......
  • P4690 镜中的昆虫 (动态区间颜色数) 题解
    Statement区间涂颜色区间颜色数Solution\(O(\text{polysqrt})\)略。\(O(\text{polylog})\)颜色段均摊有两层含义:随机数据下:任意时刻的颜色段个数期望\(O(\logn)\)非随机数据下:每次推平时访问的颜色段个数均摊\(O(n)\)首先维护每个点\(i\)的\(pre_i\),一次询......
  • Codeforces Rund 977 div2 个人题解(A~E1)
    CodeforcesRund977div2个人题解(A,B,C1,C2,E1)Dashboard-CodeforcesRound977(Div.2,basedonCOMPFEST16-FinalRound)-Codeforces火车头#define_CRT_SECURE_NO_WARNINGS1#include<algorithm>#include<array>#include<bitset>#includ......
  • 【题解】C - STEP
    目录题目内容DescriptionInputOutput数据规模与约定做法一思路代码做法2思路代码题目内容原题:洛谷P6492Description给定一个长度为\(n\)的字符序列\(a\),初始时序列中全部都是字符L。有\(q\)次修改,每次给定一个\(x\),若\(a_x\)为L,则将\(a_x\)修改成R,否则将\(a_x\)......
  • 常见问题解决 --- maven手动安装依赖jar包报错
    报错内容:执行命令mvninstall:install-file-DgroupId=com.beidouapp-DartifactId=SSDK-Dversion=4.0.2.0 -Dfile=C:\1\SSDK-Release-4.0.2.0.jar-Dpackaging=jar报错Unknownlifecyclephase“.ggstar“.Youmustspecifyavalidlifecyclephaseoragoal原因:在pow......
  • CCF-CSP认证资格考试题解系列——第4次第2题数字排序
    #include<iostream>#include<algorithm>usingnamespacestd;structre{ intvalue;//数值 intnum;//次数}re[1010];boolcmp(structrea,structreb){ if(a.num==b.num)returna.value<b.value;//次数相同是小的优先 returna.num>b.num;//次数不相同是次数优......
  • CCF-CSP认证资格考试题解系列——第4次第3题节日
    #include<iostream>usingnamespacestd;intm[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};intis_run(intyear){ if(year%400==0||(year%4==0&&year%100))return1; return0;}intgetdays(intyear,intmonth){ if(month==2)returnm[month]+i......
  • gym103687D / QOJ3998 The Profiteer
    题意有\(n\)个物品,和一个背包容量上限\(m\)。每个物品有价值\(v_i\)和体积\(a_i\)。你需要选择一段区间\([l,r]\),将这个区间内的体积变为\(b_i\),剩下的不变。然后你对这\(n\)个物品做背包,设背包容量结果为\(f(i)\),需要求出有多少段区间使得\(\dfrac{\sum_{i=1}^mf(......