ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AT3859 [AGC020E] Encoding Subsets

2022-08-06 19:01:44  阅读:31  来源: 互联网

标签:string Subsets Encoding ll AT3859 枚举 循环 字符串 sum


有一道题 也是字符串的压缩,但是要求的是压缩后的最短长度,然后做法是区间 \(\tt DP\)。故考虑区间 \(\tt DP\)(应该比较显然看出)。

我们先把问题弱化:去掉“包含”的条件,对单个字符串求答案。

考虑如刚刚那题,记录 \(f_{l,r}\) 代表一个区间的答案。

但是这一个不够(我考场上在这里挣扎了许久),还要用 \(g_{l,r}\) 代表 不是由多个压缩合并而成的压缩的答案

转移不难。

  • \(f_{l,r}\) 的转移:枚举断点 \(k\in[l,r)\),\(f_{l,r}=\sum g_{l,k}f_{k+1,r}\)。
  • 原因:如果使用 \(f\) 来代替这个式子里面的 \(g\),那样会算重。
  • \(g_{l,r}\) 的转移:枚举 \(k\in[1,r-l+1]\) 使得 \(S_{l\cdots l+k-1}\) 是 \(S_{l\cdots r}\) 的循环节(即它会重复很多遍),\(g_{l,r}=\sum f_{l,l+k-1}\)。
  • 原因:\(g\) 的来源就是每一种可能的循环节情况之和。

考虑原问题。

我们不妨用一个字符串 \(S\) 代替原先的状态 \(\{l,r\}\),代表 \(S\) 的答案。

  • \(f_S\) 的转移:类似的套路枚举断点,然后直接 string::substr 找到 \([l,k]\) 和 \((k+1,r]\) 的两个子串。
  • \(g_S\) 的转移:有点改变(但是不难想),枚举一个可能的循环的位置 \(k\)(只需要满足 \(k\mid r-l+1\) 即可)然后考虑有一个字符串 \(T\) 作为循环节,对于它的任意一位
  1. 找到每个 \(T\) 需要覆盖上的字符串 \(T^{\prime}\) 的对应位。
  2. 如果全部都是 \(1\),那这一位就可以取到 \(1\)(如果有一位是 \(0\),根据“包含”的规则,无法将其改变成 \(1\)。)
  3. 一定可以取到 \(0\)(如果有一位是 \(1\),根据“包含”的规则,可以将其改变成 \(1\)。)
  • 找到对于每个可能的 \(k\mid r-l+1\),对应的循环节字符串 \(T\) 的 \(1\) 的个数 \(x\),那么 \(g_{l,r}=\sum2^xf_T\)。
  • 原因:\(2^x\) 可以代表 \(T\) 包含几个字符串(原因:这些位置有两种选择,其它位置有一种选择)

对于状态的存储,考虑记忆化搜索,然后 unordered_map<string,int> 解决。

#import<iostream>
#import<unordered_map>
using namespace std;

using ll = long long;
const ll mod = 998244353;

string st;
unordered_map<string,int> f,g;

ll F(string s);
ll G(string s);

ll F(string s){
	if(f.find(s) != f.end()) return f[s];
	int sum = 0,len = s.length();
	for(int i = 1;i <= len;++i)
		(sum += G(s.substr(0,i)) * F(s.substr(i,len - i + 1)) % mod) %= mod;
	return f[s] = sum;
}

ll G(string s){
	if(g.find(s) != g.end()) return g[s];
	int sum = 0,len = s.length();
	for(int i = 1;i < len;++i) if(len % i == 0){
		string str = "";
		for(int p = 0;p < i;++p){
			bool f = 1;
			for(int q = p;q < len;q += i)
				f &= (s[q] - '0');
			str += f ? '1' : '0';
		}
		(sum += F(str)) %= mod;
	}
	return g[s] = sum;
}

void init(){ f[""] = g[""] = g["0"] = 1; g["1"] = 2; }

int main(){
	cin >> st;
	init();
	cout << F(st) << endl;
	return 0;
}

标签:string,Subsets,Encoding,ll,AT3859,枚举,循环,字符串,sum
来源: https://www.cnblogs.com/zeno6174/p/AT3859.html

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有