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\),那么存在两种转移:

  1. 删除下一个点,\(dp[i][j] = min(dp[i][j],dp[i-1][j]+1)\)
  2. 走到自动机的下一个点,\(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】的更多相关文章

  1. 【bzoj1030】[JSOI2007]文本生成器 AC自动机+dp

    题目描述 JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固 ...

  2. HDU 2457 DNA repair(AC自动机+DP)题解

    题意:给你几个模式串,问你主串最少改几个字符能够使主串不包含模式串 思路:从昨天中午开始研究,研究到现在终于看懂了.既然是多模匹配,我们是要用到AC自动机的.我们把主串放到AC自动机上跑,并保证不出现 ...

  3. HDU2296——Ring(AC自动机+DP)

    题意:输入N代表字符串长度,输入M代表喜欢的词语的个数,接下来是M个词语,然后是M个词语每个的价值.求字符串的最大价值.每个单词的价值就是单价*出现次数.单词可以重叠.如果不止一个答案,选择字典序最小 ...

  4. 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂

    [题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...

  5. 【hdu2457】ac自动机 + dp

    传送门 题目大意: 给你一个字符主串和很多病毒串,要求更改最少的字符使得没有一个病毒串是主串的子串. 题解: ac自动机 + dp,用病毒串建好ac自动机,有毒的末尾flag置为true 构建fail ...

  6. luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP)

    luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP) Luogu 题解时间 难点在于式子转化,设有c个满足的子串,即求最大的 $ ans = \sqrt[c]{\prod_{ ...

  7. POJ1625 Censored!(AC自动机+DP)

    题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...

  8. HDU2296 Ring(AC自动机+DP)

    题目是给几个带有价值的单词.而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么? 依然是入门的AC自动机+DP题..不一样的是这题要输出具体方案,加个 ...

  9. HDU2457 DNA repair(AC自动机+DP)

    题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...

  10. hdu 4117 GRE Words AC自动机DP

    题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...

随机推荐

  1. java对象

    原文链接http://zhhll.icu/2020/04/26/java%E5%9F%BA%E7%A1%80/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/java%E5% ...

  2. tp where使用数组条件,如何设置or,and

    1 //where条件数组拼接 2 $where['status'] = 1; 3 $maps['id'] = ['in', implode(',', $r_ids)]; 4 $maps['uid'] ...

  3. WPF DataGrid与ListView性能对比与场景选择

    开门见山的说 性能对比: 在Demo中,DataGrid与ListView默认开启虚拟化(可以理解为动态渲染,类似懒加载只渲染屏幕可以看见的地方) DataGrid渲染10列50行随机字符280ms ...

  4. Linux Clone函数

    Linux Clone函数 之前某一次有过一次面试,问了内核中是怎么创建命名空间的? 下面就来扒一扒clone的精髓,以及如何通过它创建命名空间. 目录 Linux Clone函数 使用clone创建 ...

  5. linux最大打开文件句柄数

    linux最大打开文件句柄数,即打开文件数最大限制,就是规定的单个进程能够打开的最大文件句柄数量(Socket连接也算在里面,默认大小1024) liunx中文件句柄有两个限制,一种是用户级的,一种是 ...

  6. 解压rpm文件

    rpm2cpio zabbix-2.2.2-0.el6.zbx.src.rpm |cpio -div

  7. 【Linux】awk想打印制定列以后的所有列

    今天偶然研究awk,有一个文件,文件内容是全篇的1 2 3 4 5 6 7 8 9 0 现在想打印除了第一列意外的所有列 文件内容: [root@localhost ~]# cat test.txt ...

  8. DC-DC变换器,24v转5v稳压芯片,3A输出电流

    在24V输入中,比较合适的LDO可以选择:PW6206,输出电压3V,3.3V,5V 输入电压最高40V,功耗也低4uA左右,采用SOT23-3封装. PW6206系列是一个高精度,高输入电压低静态电 ...

  9. 一个非常棒的Go-Json解析库

    json是一种数据格式,经常被用作数据交换,页面展示,序列化等场景,基本每种语言都有对应的json解析框架,Go语言也不例外,并且内置了json库,基本能够满足一些普通开发场景,但有些复杂场景下就不太 ...

  10. uni-app开发经验分享十三:实现手机扫描二维码并跳转全过程

    最近使用 uni-app 开发 app ,需要实现一个调起手机摄像头扫描二维码功能,官网API文档给出了这样一个demo: // 允许从相机和相册扫码 uni.scanCode({ success: ...