CF506E Mr. Kitayuta's Gift

1, Title

Click here to see the question

2, Solution

A question that deeply baptized me is a rare good question with both thinking difficulty and code difficulty!

Consider my palindrome string first! First, consider how to count. The questions tell you that you only care about the final state. We count the final state directly. Considering the enumeration method to determine the position of the original character in the final sequence, the scheme can be determined by simple counting.

Use \ (dp \) to optimize this process. Set \ (f_{i,l,r} \) as the first \ (i \) and last \ (i \) characters of the final sequence, and the number of schemes in which the interval \ ([l,r] \) is not determined in the original string. Set \ (g_, i \) to represent the number of schemes in which the first \ (i \) and last \ (i \) characters of the final sequence are considered, and the original string has been used up.

In order not to be too heavy, we need to express a scheme only in one way. Even if it can be expressed in many "ways", we also specify a way to store it:

If \ (s_l=s_r,r-l\leq 1 \), you can directly go to the final state, transfer \ (f \) to \ (g \), and fill in different character pairs (\ (25 \):

\[g_{i+1}\leftarrow f_{i,l,r} \]

\[f_{i+1,l,r}\leftarrow 25\cdot f_{i,l,r} \]

If \ (s_l=s_r,r-l\geq 2 \), you can take out both sides for pairing, or fill in different character pairs (\ (25 \)):

\[f_{i+1,l+1,r-1}\leftarrow f_{i,l,r} \]

\[f_{i+1,l,r}\leftarrow 25\cdot f_{i,l,r} \]

If \ (s_l\not=s_r \), you can take it out and match it with any character, or you can fill in different character pairs (\ (24 \)):

\[f_{i+1,l+1,r}\leftarrow f_{i,l,r} \]

\[f_{i+1,l,r-1}\leftarrow f_{i,l,r} \]

\[f_{i+1,l,r}\leftarrow 24\cdot f_{i,l,r} \]

The last is the transfer of \ (g \), which can be filled in by \ (26 \): \ (g_{i+1}\leftarrow 26\cdot g_i \)

The above transfer can be directly nested matrix multiplication, with time complexity \ (O(m^6\log n) \)

Please allow me to steal the wave diagram and continue to optimize it. We can draw the transfer image. The red dot in the figure below represents the transfer point of the left and right end points subtracting \ (1 \), and the green dot represents the transfer point of the left and right end points subtracting \ (2 \). The answer is the number of path schemes from the starting point to the end point on this diagram:

Because the original string size is fixed, if there are \ (K \) red dots on a path, there must be \ (\ lfloor\frac{m-k}{2}\rfloor \) green dots. The number of path schemes is closely related to the self ring, that is, to the number of red and green points passed, and has little to do with the edge with only \ (1 \) weight. Therefore, the number of essentially different paths is only \ (O(m) \).

Therefore, the number of occurrences of each path can be counted, and the answer can be calculated by single moment multiplication. The time complexity \ (O(m^4\log m) \) can be calculated by simple multiplication principle. The step of counting the path can be searched by memory. Let \ (H {i, l,r} \) be \ (I \) green dots and consider the number of schemes of interval \ ([l,r] \).

For further optimization, the whole \ (dp \) can be considered. Because their transfer rules are the same, we build it on a diagram:

The \ (i \) red dot \ (/ \) green dot from the back to the front indicates that there are still \ (i \) red dots \ (/ \) green dots on the path. The edge connecting the red dot and the green dot can be set to the number of such paths. Note that no red dot needs to be initialized on the green dot. Run the graph with matrix acceleration \ (O(m^3\log n) \)

If there is an odd palindrome string at the end, the illegal situation can be subtracted, that is, the last step is to transfer to the end point through the green dot with length \ (2 \), then we remove the self ring of the end point, and then only retain the path to these green dots. Similarly, we can run the moment multiplication to get the answer.

Implementation details: since the graph we built is an upper triangle (only the one with small number will be transferred to the one with large number), we can only multiply the triangle when multiplying. It is said that the constant is directly as small as \ (\ frac{1}{6} \)

3, Summary

What I am missing in this topic is the key de reprocessing in that step. How to express the scheme is very important. If you only care about the final scheme, there are many methods in the process that can force a certain method to achieve the final scheme.

Other design skills: visual representation of design graph theory model; Division of equivalence classes; The transfer method is the same, using the whole \ (dp \)

In fact, the model of this problem can also be called finite state automata. The string problem can be considered in this direction.

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 205;
const int MOD = 1e4+7;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,g[M][M],f[M],h[M][M][M];char s[M];
int ceil(int x)
{
	return (x>>1)+(x&1);
}
int dfs(int i,int l,int r)
{
	if(i<0 || l>r) return 0;
	if(h[i][l][r]!=-1) return h[i][l][r];
	int &o=h[i][l][r];o=0;
	if(l==1 && r==m) return o=!i;
	if(l>1 && r<m && s[l-1]==s[r+1])
		o=(o+dfs(i,l-1,r+1))%MOD;
	if(l>1 && s[l-1]!=s[r])
		o=(o+dfs(i-1,l-1,r))%MOD;
	if(r<m && s[l]!=s[r+1])
		o=(o+dfs(i-1,l,r+1))%MOD;
	return o;
}
void qkpow(int b)
{
	while(b>0)
	{
		if(b&1)
		{
			int a[M]={};
			for(int i=1;i<=k;i++)
			for(int j=1;j<=k;j++)
				a[i]=(a[i]+f[j]*g[j][i])%MOD;
			swap(a,f);
		}
		int a[M][M]={};
		for(int i=1;i<=k;i++)
		for(int j=i;j<=k;j++)
		for(int l=j;l<=k;l++)
			a[i][l]=(a[i][l]+g[i][j]*g[j][l])%MOD;
		swap(a,g);
		b>>=1;
	}
}
signed main()
{
	scanf("%s",s+1),m=strlen(s+1);n=read();
	memset(h,-1,sizeof h);k=m+ceil(m);
	//[1,m) red ; [m,k) green ; k end
	for(int i=0;i<m;i++)
	{
		int c=0;
		for(int j=1;j<=m;j++)
		{
			c=(c+dfs(i,j,j))%MOD;
			if(j<m && s[j]==s[j+1])
				c=(c+dfs(i,j,j+1))%MOD;
		}
		if(!i)
		{
			f[m]=c;g[k][k]=26;
			for(int j=m;j<k;j++)
				g[j][j+1]=1,g[j][j]=25;
		}
		else
		{
			g[i][k-ceil(m-i)]=c;g[i][i]=24;
			if(i>1) g[i-1][i]=1;
			else f[i]=1;
		}
	}
	int F[M]={},G[M][M]={};
	memcpy(F,f,sizeof F);
	memcpy(G,g,sizeof G);
	qkpow(ceil(n+m));
	if((n+m)%2==0)//even length
	{
		printf("%d\n",f[k]);
		return 0;
	}
	int ans=f[k];
	memcpy(f,F,sizeof f);
	memcpy(g,G,sizeof g);
	//build the new graph,containing illegal roads
	for(int i=0;i<m;i++)
	{
		int c=0;
		for(int j=1;j<m;j++) if(s[j]==s[j+1])
			c=(c+dfs(i,j,j+1))%MOD;
		if(i) g[i][k-ceil(m-i)]=c;
		else f[m]=c,g[k][k]=0;
	}
	qkpow(ceil(n+m));
	printf("%d\n",(ans-f[k]+MOD)%MOD);
}

Tags: string dp

Posted on Wed, 03 Nov 2021 20:41:51 -0400 by maxedison