CF 1400F x-prime Substrings 题解【AC自动机+DP】
CF 1400F.x-prime Substrings
题意:
给定一个由\('1'\)到\('9'\)组成的字符串\(s\)和一个数\(x\),定义一个串为\(x-prime\)串,当且仅当这个串上的数字和为\(x\),且任意一个不等于本身的子串的和都不是\(x\)的因子,问最少删多少个数字可以使得串\(s\)的任何子串都不是\(x-prime\)串
\(1 \le |s| \le 1000,1 \le x \le 20\)
题解:
由于\(x\)很小,所以我们可以枚举所有\(x-prime\)串,然后把所有的\(x-prime\)串放到\(Trie\)里面去,因为我们需要原串中没有\(x-prime\)串,考虑把所有\(x-prime\)串建AC自动机,然后我们跑一遍\(dp\),\(dp[i][j]\)表示\(s\)串中的第\(i\)位匹配了自动机上的状态\(j\)的情况下的最小删除数量
枚举自动机所有的状态\(j\),那么存在两种转移:
- 删除下一个点,\(dp[i][j] = min(dp[i][j],dp[i-1][j]+1)\)
- 走到自动机的下一个点,\(dp[i][trans[j]] = min(dp[i][trans[j],dp[i-1][j])\)
其中第二种转移必须要求AC自动机的下一个点没有匹配到任何的\(x-prime\)串
由于每个状态只与上一层有关,可以把\(dp\)数组变为滚动数组
那么,这道题就完成了
view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define endl "\n"
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%I64d",&x)
#define scs(x) scanf("%s",s)
#define pii pair<int,int>
#define pll pair<LL,LL>
#ifndef ONLINE_JUDGE
#define cout cerr
#endif
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x) cerr << #x << " = " << x << endl
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> vector<T>& operator << (vector<T> &__container, T x){ __container.push_back(x); return __container; }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; return out; }
const int MAXN = 1111;
struct AC_automaton{
int ch[MAXN<<5][9],fail[MAXN<<5],tot;
bool tag[MAXN<<5];
void insert(string s){
int p = 0;
for(int i = 0; i < (int)s.size(); i++){
int c = s[i] - '1';
if(!ch[p][c]) ch[p][c] = ++tot;
p = ch[p][c];
}
tag[p] = true;
}
void build_fail(){
queue<int> que;
for(int i = 0; i < 9; i++) if(ch[0][i]) que.push(ch[0][i]);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = 0; i < 9; i++){
if(!ch[u][i]) { ch[u][i] = ch[fail[u]][i]; continue; }
que.push(ch[u][i]);
int v = ch[u][i];
int pre = fail[u];
while(pre and !ch[pre][i]) pre = fail[pre];
fail[v] = ch[pre][i];
tag[v] |= tag[fail[v]];
}
}
}
int DP(string &s){
vector<int> f(tot+1,INF);
f[0] = 0;
for(char &c : s){
int x = c - '1';
vector<int> next_f(tot+1,INF);
for(int i = 0; i <= tot; i++){
if(f[i]==INF) continue;
cmin(next_f[i],f[i]+1);
if(!tag[ch[i][x]]) cmin(next_f[ch[i][x]],f[i]);
}
f.swap(next_f);
}
return *min_element(all(f));
}
}aho;
bool check(string &dig, int x){
vector<int> pre(dig.size());
pre[0] = dig[0] - '0';
for(int i = 1; i < (int)dig.size(); i++) pre[i] = pre[i-1] + dig[i] - '0';
for(int i = 0; i < (int)dig.size(); i++){
for(int j = i; j < (int)dig.size(); j++){
int S = pre[j] - (i==0?0:pre[i-1]);
if(S!=x and x%S==0) return false;
}
}
return true;
}
void search_dig_string(string &dig, int sum, int x){
if(sum==x){
if(check(dig,x)) aho.insert(dig);
return;
}
for(int i = 1; i < 10; i++){
if(sum+i>x) return;
dig.push_back(i+'0');
search_dig_string(dig,sum+i,x);
dig.pop_back();
}
}
void solve(){
string str;
int x;
cin >> str >> x;
string dig("");
search_dig_string(dig,0,x);
aho.build_fail();
cout << aho.DP(str) << endl;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}
CF 1400F x-prime Substrings 题解【AC自动机+DP】的更多相关文章
- 【bzoj1030】[JSOI2007]文本生成器 AC自动机+dp
题目描述 JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固 ...
- HDU 2457 DNA repair(AC自动机+DP)题解
题意:给你几个模式串,问你主串最少改几个字符能够使主串不包含模式串 思路:从昨天中午开始研究,研究到现在终于看懂了.既然是多模匹配,我们是要用到AC自动机的.我们把主串放到AC自动机上跑,并保证不出现 ...
- HDU2296——Ring(AC自动机+DP)
题意:输入N代表字符串长度,输入M代表喜欢的词语的个数,接下来是M个词语,然后是M个词语每个的价值.求字符串的最大价值.每个单词的价值就是单价*出现次数.单词可以重叠.如果不止一个答案,选择字典序最小 ...
- 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂
[题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...
- 【hdu2457】ac自动机 + dp
传送门 题目大意: 给你一个字符主串和很多病毒串,要求更改最少的字符使得没有一个病毒串是主串的子串. 题解: ac自动机 + dp,用病毒串建好ac自动机,有毒的末尾flag置为true 构建fail ...
- luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP)
luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP) Luogu 题解时间 难点在于式子转化,设有c个满足的子串,即求最大的 $ ans = \sqrt[c]{\prod_{ ...
- POJ1625 Censored!(AC自动机+DP)
题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...
- HDU2296 Ring(AC自动机+DP)
题目是给几个带有价值的单词.而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么? 依然是入门的AC自动机+DP题..不一样的是这题要输出具体方案,加个 ...
- HDU2457 DNA repair(AC自动机+DP)
题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...
- hdu 4117 GRE Words AC自动机DP
题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...
随机推荐
- Windows 2008 Server R2双网卡负载均衡
源文档 <http://blog.sina.com.cn/s/blog_6025f5690101apwd.html>
- java8新特性之stream流
Stream 流是 Java 8 提供给开发者一套新的处理集合的API,他把我们将要处理的集合作为流,就像流水线一样,我们可以对其中的元素进行筛选,过滤,排序等中间操作,只不过这种操作更加简洁高效. ...
- 面试官:Netty的线程模型可不只是主从多Reactor这么简单
笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...
- (十二)random模块
大致有以下几个函数: print(random.random()) #0到1的浮点型 print(random.randint(1,6)) #1到6的整型 print(random.randrange ...
- ElasticJob 快速上手
1. ElasticJob 是什么 ElasticJob 是一个分布式调度解决方案,由两个相互独立的子项目 ElasticJob-Lite 和 ElasticJob-Cloud 组成. Elasti ...
- 【Linux】以001格式循环到100保证位数是3位
这里有一个前提,要保证数位是相同的 确实数字是1-100 但是数位是不同的,需要统一一下位数必须是3位的 这个问题在很多论坛上用的都是printf这个命令,确实可以达到这个效果,但是没有我下面介绍的 ...
- 【ASM】asm中添加 diskgroup
环境:rhel5 Oracle10g rac 背景:在esxi中添加了一个20g的共享磁盘准备存放归档日志用 一.准备环境 1.添加共享磁盘并且格式化 #fdisk -l查看磁盘已经添加完成 #fdi ...
- 数据分析 Pandas 简介和它的的数据结构
本文主要讲Pandas 的Series和DataFrame 的相关属性和操作 1.Series的相关属性和操作# --Series是一种类似于一维数组的对象,只能存放一维数组!由以下两部分组成:# v ...
- linux搭建简单samba服务器
1.安装需要的软体 yum install -y samba samba-client samba-common 2.创建samba需要的本地用户,创建samba服务使用的目录 Linux系统文件的读 ...
- vue-cli3x4x修改本地端口port
一.推荐方法 "scripts": { "serve": "vue-cli-service serve --port 3000", &quo ...