ICode9

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

AT3859 [AGC020E] Encoding Subsets

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

标签: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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

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

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

ICode9版权所有