CodeForces - 1400F x-prime Substrings(AC自动机+dp)

题目链接:点击查看

题目大意:给出一个只由数字 1 ~ 9 组成的字符串 s,首先规定 f( l , r ) 为字符串 s 的区间 [ l , r ] 中的数位和,再规定 x-prime 需要同时满足以下条件:

  1. f( l1 , r1 ) = x
  2. 不存在 ( l2 , r2 ),使得:
    1. l1 <= l2 <= r2 <= r1
    2. f( l2 , r2 ) != x
    3. 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;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/108242747