题目链接:点击查看
题目大意:给出一个只由数字 1 ~ 9 组成的字符串 s,首先规定 f( l , r ) 为字符串 s 的区间 [ l , r ] 中的数位和,再规定 x-prime 需要同时满足以下条件:
- f( l1 , r1 ) = x
- 不存在 ( l2 , r2 ),使得:
- l1 <= l2 <= r2 <= r1
- f( l2 , r2 ) != x
- x 可以被 f( l2 , r2 ) 整除
问最少删掉字符串 s 中的多少个字母,可以使得整个字符串中不含有 x-prime
题目分析:首先对 x ∈ [ 1 , 20 ] 都打个表,发现当 x = 19 时,有最多的 x-prime ,为 2399 个,这样对于每个 x 就可以将需要删除的匹配串暴力dfs出来,这样问题就变得和之前一道题目很像了:https://blog.csdn.net/qq_45458915/article/details/104243061
只不过那道题目是对相应的位置修改为别的字母,这个题目是直接将相应位置删除了,在 dp 转移的过程中有点小的区别,其他的几乎都一模一样了
dp[ i ][ j ] 代表到了字符串 s 的第 i 个位置,状态为 j 时的最小删除数,转移的话,因为是可以删除,所以 dp[ i + 1 ][ j ] = dp[ i ][ j ] + 1 这个代表需要将第 i + 1 位删除,而当 trie[ j ][ s[ i ] ] 不是 x-prime 时,可以不用删除,也就是 dp[ i + 1 ][ trie[ j ][ s[ i ] ] ] = dp[ i ][ j ]
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e3+100;
const int M=5e3+100;
int trie[M][10],fail[M],cnt;
bool vis[M];
char s[M],str[N];
int dp[N][M],x;
void insert_word()
{
int len=strlen(s);
int pos=0;
for(int i=0;i<len;i++)
{
int to=s[i]-'0';
if(!trie[pos][to])
trie[pos][to]=++cnt;
pos=trie[pos][to];
}
vis[pos]=true;
}
void getfail()
{
queue<int>q;
for(int i=0;i<10;i++)
{
if(trie[0][i])
{
fail[trie[0][i]]=0;
q.push(trie[0][i]);
}
}
while(!q.empty())
{
int cur=q.front();
q.pop();
vis[cur]|=vis[fail[cur]];
for(int i=0;i<10;i++)
{
if(trie[cur][i])
{
fail[trie[cur][i]]=trie[fail[cur]][i];
q.push(trie[cur][i]);
}
else
trie[cur][i]=trie[fail[cur]][i];
}
}
}
void dfs(int sum,int step)
{
if(sum>x)
return;
if(sum==x)
{
s[step]=0;
for(int i=0;i<step;i++)
{
int d=0;
for(int j=i;j<step;j++)
{
d+=s[j]-'0';
if(x%d==0&&x!=d)
goto end;
}
}
insert_word();
end:;
return;
}
for(int i=1;i<=9;i++)
{
s[step]=i+'0';
dfs(sum+i,step+1);
}
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
scanf("%s%d",str,&x);
dfs(0,0);
getfail();
int n=strlen(str);
memset(dp,inf,sizeof(dp));
dp[0][0]=0;
for(int i=0;i<n;i++)
for(int j=0;j<=cnt;j++)
if(dp[i][j]<inf)
{
dp[i+1][j]=min(dp[i+1][j],dp[i][j]+1);//得删
int nj=trie[j][str[i]-'0'];
if(!vis[nj])//不用删
dp[i+1][nj]=min(dp[i+1][nj],dp[i][j]);
}
int ans=inf;
for(int i=0;i<=cnt;i++)
ans=min(ans,dp[n][i]);
printf("%d\n",ans);
return 0;
}