容斥原理

给你一个字符串中有多少个不重复的子序列

一个字符串中算上重复的和空串的序列,总共有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;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值