(The 11th Finals of the Blue Bridge Cup) Question D: Essence Ascending Sequence (Dynamic Programming)

First give the string in the title: tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaqahahndsiknipzssoywakgnfjwlihwlhtwoul

Analysis: Although this is just a fill-in-the-blank question, I think it still has a certain meaning for thinking, so I will analyze it as a normal big question today:

Let f[i] represent an essentially different incremental subsequence ending with i , here we first analyze a string bab, obviously f[1]=1, f[2]=1, f[1]=1 is Because there is only b, f[2]=1 because there is only a, then f[3]=? , if it is 1, then there is only ab, if it is 2, then it contains two increasing subsequences of ab and b, but obviously b has been calculated before, so if we make f[3]=2 here If it is, the calculation will be repeated, because if the preceding and following letters overlap, we only need to consider it once, so here I attribute it to the contribution of the preceding letters , that is to say, f[3]=1 in the string analyzed above, That is, only the case of ab is included. If we can find all f[i], we can know from the definition of the f array that we can get the answer by summing all the f arrays at the end .

Let's proceed to the derivation of the dynamic transfer equation:

Now take abcsca as an example

f[1]=1(a)

f[2]=2(b, (f[1] followed by b)ab)

f[3]=4(c, (f[1] followed by c)ac, (f[2] followed by c)bc,abc)

f[4]=8(s, (f[1] followed by s)as, (f[2] followed by s)bs,abs (f[3] followed by s)cs,acs,bcs,abcs ) 

f[5]=0 (none)

f[6]=0 (none)

It is found that when the second c is encountered, the contribution of the second c becomes 0. In other words, the contribution of c is in the previous c, because if only the first c and its occurrence position are considered For characters, the contribution ending with the second c is the same as the contribution ending with the first c. The position where the first c appears is 3, then the second c is formed by the character before the previous c appears. The incrementing subsequence is repeated, these have been calculated in the previous c, so the contribution of the current c should be considered from the position after the last occurrence of c , if a character lexicographical order is less than c And appearing after the previous c, adding a c after all the essentially different incrementing subsequences ending with this character can form a new incrementing subsequence, which should belong to the contribution of the current c , if this character is greater than or equal to c Regardless , according to this method, we can obtain all the f arrays, so that we can get the final answer. Note that if we update this way, we can only initialize the first occurrence of a letter to 1, and the second occurrence cannot be initialized to 1, because it has been calculated before.

Here is the code for this idea:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=303;
long long f[N];//f[i]代表以i结尾的本质不同的序列数 
int last[30];//last[i]代表字符i最后一次出现的位置 
int main()
{
	string s;
	cin>>s;
	long long len=s.size();
	s=" "+s;//让下标从1开始
	for(int i=1;i<=len;i++)
	{
		if(!last[s[i]-'a'+1])//如果这个字符没有出现过,则单个字符的贡献应该属于这个字符,反之由于已经被计算过则不能再初始化为1 
			f[i]=1;//初始化为1(只包含自身)
		for(int j=last[s[i]-'a'+1]+1;j<i;j++)//从上次出现这个字母的后一个位置开始更新f[i] 
			if(s[i]>s[j]) f[i]+=f[j];
		last[s[i]-'a'+1]=i;//记录该字母最后一次出现的位置
	}
	long long ans=0;
	for(int i=1;i<=len;i++)
		ans+=f[i];
	cout<<ans;
	return 0;
}

Of course, we can also consider directly from the front to the back. For example , if we consider updating f[i], we traverse 1~i-1. If s[j]<s[i], then we directly add f[j], It is equivalent to adding a character s[i] directly to the end of the legal sequence ending with the jth character, which is also a legal sequence. If s[i]==s[j], we subtract f[j], Because when we use f[1~j-1] to update f[i], it is equivalent to using f[j] to update f[i], because the cost of the last letter is s[i] has been calculated into f In [j], so we need to subtract this part . In fact, the essence of thinking like this is the same as the above, just depends on how you think about it. Since we add the overlapping part first and then subtract the overlapping part, we There is no need to query the position of the last occurrence of the current letter as above, so we should initialize f[i] to 1 at the beginning, representing the contribution of each letter (including only the letter itself).

Here is the code for this method:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=303;
long long f[N];//f[i]代表以i结尾的本质不同的序列数 
int main()
{
	string s;
	cin>>s;
	long long len=s.size();
	s=" "+s;//让下标从1开始 
	for(int i=1;i<=len;i++) 
	{
		f[i]=1;//初始化为1(只包含自身)
		for(int j=1;j<i;j++)
		{
			if(s[i]==s[j])//减去重复计算的部分
				f[i]-=f[j];
			else if(s[i]>s[j])
				f[i]+=f[j];
		}
	}
	long long ans=0;
	for(int i=1;i<=len;i++)
		ans+=f[i];
	cout<<ans;
	return 0;
}

Finally, you can directly put the string I gave at the beginning as input into the equation to get the answer: 3616159

Guess you like

Origin blog.csdn.net/AC__dream/article/details/123999576