给你一个字符串中有多少个不重复的子序列
一个字符串中算上重复的和空串的序列,总共有2^n个子序列。
很好理解 :字符串 s 求它的子序列,
每个子序列都基于之前的序列上来得出 1->n
S: asd
1:a 放或者不放 得出子序列 ‘a’ 和 空串‘ ’
2: s在1的基础上,选择放或者不放 得出子序列 ‘a’ 'as' ' ' 's'
结论 s[ i ] = s[i - 1]*2;
s[n] 为 所求的所有的子序列个数。(不计空串‘ ’的话要减一)
但是:
当s = aas的时候
字符串的子序列不计重复的个数是 4个 而不是 2^3 = 8个,
a ,aa ,as ,aas。
怎么办?
容斥原理去掉重复。
还是以 aas作为例子
它的全部子序列:
1:' ' 'a' 2
2:'a' 'aa' ' ' 'a' 4
3:' a' 'as' 'aas' 'aa ' ' ' 's' 'as' 8
显然有重复的序列存在,存在的原因是有两个a,当第一个a不放,第二个a放的时候,它得出的所有的子序列等于 第一个a选择时的结果(在这里出现了重复子序列)
所以当有重复字母出现的时候
s[i] = 2*s[i-1]之余还要减去重复部分,也就是要减去和s[ i ] 字符相同的s[ k ](s[k] == s[i],k < i),最近的前继个数
s[ i ] = 2*s[i-1] - s[k - 1]; (为什么是s[k - 1]?因为s[k] 选择放的时候的策略是不能被消去的,你只能消去s[ k ]不放的时候的策略)
#include<stdio.h>
#include<string.h>
using namespace std;
char s[105];
__int64 ss[105];
int main()
{
//freopen("data.in", "r", stdin);
//freopen("data.out", "w", stdout);
ss[0] = 1;
while(~scanf("%s",s+1))
{
int len = strlen(s+1);
for(int i = 1;i <= len; i++)
{
int temp = 0;
for(int j = i-1;j > 0; j--)
{
if(s[i] == s[j])
{
temp = j;
break;
}
}
if(temp)ss[i] = ss[i-1]*2 - ss[temp-1];
else ss[i] = ss[i-1]*2;
}
printf("%I64d\n",ss[len]-1);
}
return 0;
}