AT4108 [ARC094D] Normalization
AT4108 [ARC094D] Normalization
套路了,设 、、 分别为 、、,则所有操作得到的数字串的和必然模 同余。
且操作得到的数字串必然有相邻相等的数字(注意特判开始是否有相邻相等的字符)。
根据暴力输出情况发现当 时上述条件为充分条件。
考虑归纳证明: 如果 时条件充分,长度为 的字符串 和 , 一定能够经过若干次操作将其首字母换成 的首字母,由于 时满足充分,即 和 后缀 满足充分,此时首字母相等显然也充分,证毕。
故从 (满足 可操作)可变到 ,需充分满足上面两个限制。
故当 时 暴力。
否则根据这两个限制 DP
,答案即为满足数位和模 同余初始串且含有相邻相等的数字的数字串个数。
考虑容斥,即数位和模 同余初始串的数字串个数 数位和模 同余初始串且不含有相邻相等的数字的数字串个数。
对于前面的,答案显然为 ,即任意枚举 位,最后一位视情况而定。
对于后面的,DP
状态更少,记 表示前 位,数位和为 ,当前位为 的满足条件的数字串个数。
转移方程:枚举上一位取值,。
最后,总答案即为 (其中 表示初始字符串的数位和模 的余数,布尔变量 表示初始字符串是否有相邻相等的字符)。
时间复杂度 。
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
#define ha putchar(' ')
#define he putchar('\n')
inline int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return x * f;
}
inline void write(int x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + 48);
}
const int _ = 2e5 + 10, mod = 998244353;
int n, S, f[_][3][3], ans;
string s;
int qpow(int x, int y) {
int res = 1;
while (y) {
if (y & 1)res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
queue<string> q;
map<string, bool> mp;
char js(int x)
{
x %= 3;
if(!x) return 'a';
if(x == 1) return 'c';
return 'b';
}
void solve()
{
q.push(s);
mp[s] = 1;
while(!q.empty())
{
string nw = q.front();
q.pop();
// cout << nw << "\n";
for(int i = 0; i < n - 1; ++i)
if(nw[i] != nw[i + 1])
{
string ss = nw;
ss[i] = ss[i + 1] = js(nw[i] - 'a' + nw[i + 1] - 'a');
if(mp.find(ss) == mp.end())
{
q.push(ss);
mp[ss] = 1;
}
}
}
// for(auto v : mp) cout << v.first << "\n";
write(mp.size()), he;
}
signed main() {
cin >> s;
n = s.size();
bool flg = 0;
for (int i = 0; i < n - 1; ++i)
if (s[i] != s[i + 1]) {
flg = 1;
break;
}
if (!flg) return puts("1"), 0;
if(n <= 3) return solve(), 0;
flg = 1;
for (int i = 0; i < n - 1; ++i)
if (s[i] == s[i + 1]) {
flg = 0;
break;
}
for (int i = 0; i < n; ++i) S = (S + s[i] - 'a') % 3;
ans = qpow(3, n - 1);
for (int i = 0; i <= 2; ++i) f[0][i][i] = 1;
for (int i = 1; i < n; ++i)
for (int j = 0; j <= 2; ++j)
for (int k = 0; k <= 2; ++k)
for (int l = 0; l <= 2; ++l)
if (l != k) f[i][j][k] = (f[i][j][k] + f[i - 1][(j - k + 3) % 3][l]) % mod;
for (int i = 0; i <= 2; ++i) ans = (ans - f[n - 1][S][i] + mod) % mod;
write(ans + flg), he;
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18121987