题意:
给定只有[1,9]组成的数字串s,和一个整数x。
定义f(l,r)为数字串s[l,r]的数位和,
称s[l,r]是x-prime的,当且仅当:
1.f(l,r)=x
2.不存在两个值l2,r2,满足l<=l2<=r2<=r,且f(l2,r2)!=x,同时x能够被f(l2,r2)整除。
一次操作你可以删掉串中的一个字符,
问最少进行多少次操作,能使得串s不存在x-prime的的子串。
数据范围:|s|<=1e3,x<=20
解法:
因为x很小,每个x-prime串的长度不会超过x,
x-prime数量不会很多,可以dfs出所有x-prime串,
然后问题变为删除最少的字符,使得s串中不包含任何x-prime串.
对所有x-prime串建立ac自动机,
那么问题变为在ac自动机上按照s串走,不能走到x-prime的结尾处,
令d[i][j]表示走i步,当前在节点j位置,满足条件的最小操作次数,
对于d[i][j]:
如果要删掉s[i+1]那么d[i+1][j]=d[i][j]+1,
如果不删则d[i+1][s[i+1]],d[i+1][s[i+1]]=d[i][j]
在ac自动机上dp一下即可.
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=3e4+5;
char s[maxm];
char t[maxm];
int sum[maxm];
int a[maxm];
int n,x;
struct AC{
int a[maxm][10],fail[maxm],val[maxm],tot=0;
void init(){
for(int i=0;i<=tot;i++){
memset(a[i],0,sizeof a[i]);
val[i]=fail[i]=0;
}
tot=0;
}
void add(char *s){
int len=strlen(s);
int node=0;
for(int i=0;i<len;i++){
int v=s[i]-'0';
if(!a[node][v])a[node][v]=++tot;
node=a[node][v];
}
val[node]=1;
}
void build(){//构造fail
queue<int>q;
for(int i=0;i<10;i++){
if(a[0][i]){
q.push(a[0][i]);
}
}
while(!q.empty()){
int x=q.front();
q.pop();
val[x]|=val[fail[x]];
for(int i=0;i<10;i++){
if(a[x][i]){
fail[a[x][i]]=a[fail[x]][i];
q.push(a[x][i]);
}else{
a[x][i]=a[fail[x]][i];
}
}
}
}
//
int d[1005][maxm];
int solve(){
for(int i=0;i<=n;i++){
for(int j=0;j<=tot;j++){
d[i][j]=1e9;
}
}
d[0][0]=0;
for(int i=0;i<n;i++){
for(int j=0;j<=tot;j++){
if(d[i][j]==1e9)continue;
int v=s[i+1]-'0';
int x=a[j][v];
d[i+1][j]=min(d[i+1][j],d[i][j]+1);//删
if(!val[x]){//不删
d[i+1][x]=min(d[i+1][x],d[i][j]);
}
}
}
int ans=1e9;
for(int j=0;j<=tot;j++){
ans=min(ans,d[n][j]);
}
return ans;
}
}ac;
void dfs(int cur,int tot){
if(tot>x)return ;
if(tot==x){
for(int i=1;i<cur;i++){
sum[i]=sum[i-1]+a[i];
}
int ok=1;
for(int i=1;i<cur&&ok;i++){
for(int j=i;j<cur&&ok;j++){
if(sum[j]-sum[i-1]!=x&&x%(sum[j]-sum[i-1])==0){
ok=0;
}
}
}
if(ok){
int cnt=0;
for(int i=1;i<cur;i++){
t[cnt++]=a[i]+'0';
}
t[cnt]='\0';
ac.add(t);
}
return ;
}
for(int i=1;i<=9;i++){
a[cur]=i;
dfs(cur+1,tot+i);
}
}
signed main(){
scanf("%s",s+1);
n=strlen(s+1);
scanf("%d",&x);
dfs(1,0);
ac.build();
int ans=ac.solve();
cout<<ans<<endl;
return 0;
}