这是我的代码:
#include<iostream>
typedef long long ll;
ll fun(std::string s,ll visited[256],ll n,ll L[]){
ll ans=0;
if(n<0){
return 1;
}
//std::cout<<s.substr(0,n+1)<<" "<<n<<endl;
ans=fun(s,visited,n-1,L);
L[n]=ans;
ans=ans*2;
if(visited[int(s[n])]>=0){
ans -= L[visited[int(s[n])]];
}
visited[int(s[n])]=n;
return ans;
}
int main(){
std::string s;
std::cin>>s;
ll n=s.length();
ll visited[256];
ll L[n];
memset(visited,-1,sizeof(visited));
memset(L,-1,sizeof(L));
std::cout<<fun(s,visited,n-1,L);
return 0;
}
解释:
我从字符串的后面扫描,即从最后一个元素到第一个元素,因此发送第一个 n-1 字符以在递归中进一步扫描。
一旦n==-1 or n<0(both are same),我到达空字符串并返回1,因为没有。空字符串的子序列数为 1。
所以,从递归返回时,我们知道将当前非重复字符添加到前一个字符串会使 no 加倍。的子序列。发生加倍是因为现在我可以在所有先前子序列的末尾添加这个字符。所以,with 和 without 这个字符表示所有先前子序列的两倍。
假设当前字符不是重复的,我将前一个字符相乘。具有 2 的子序列。
在总数之后。第一个 n-1 字符的子序列的个数已经计算出来,我们将它们加倍以获得第一个 n 字符。
但是,假设当前遇到的字符(第 n 个字符)已经出现在之前的第一个 n-1 个字符中(即 - 在字符串 s[0....n-1] 中找到(注:s[n ] 是当前字符)),那么我们必须减去那些没有。可能从上一次遇到当前字符时(不包括)s 的那部分开始的子序列的数量,并且已经计算并存储在 L['this specific character'] 中。
ie - BACA - 对于给定的字符串,第 4 个 A 之前已经遇到过(从递归返回时,我们首先遇到 B,然后是 A,然后是 C,最后A),所以我们扣除了编号。计算到(不包括)第二个A(这是2(因为A之前的子序列号是2))的子序列数。
所以,每次我们都计算了编号。对于第一个 n-1 字符的子序列,我们将它们存储在数组 L 中。
注意:L[k] 存储编号。第 k 个索引之前的子序列。
我使用了访问数组来检查我当前所在的给定字符是否已经被扫描过。
在遇到当前字符时,我将访问的数组更新为当前位置的位置为n。这需要完成,因为我们必须排除重复序列。
注意:visited[] 初始化为全 -1,因为字符串 s 中任何字符的位置都是非负数(基于 0 的索引)。
总结:
How do you arrive at the number of duplicates? Let's say the last occurrence of current character at i, was at j'th position. Then, we will have duplicate subsequences: consider starting with i'th character and then all subsequences possible from [0,j-1] vs. starting at j'th character and then all subsequences possible from [0,j-1]. So, to eliminate this, you subtract the number of subsequences possible from upto (excluding) j with L[0]=1 mean that upto(excluding 0), no. of subseq are 1(empty string has 1 subsequence).