Distinct subsequence

本文介绍了一种使用动态规划算法解决字符串中独特子序列计数问题的方法。通过维护子序列数量的状态并考虑重复字符的影响,文章提供了一个有效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given a string, count the number of distinct subsequences of it ( including empty subsequence ). For the uninformed, A subsequence of a string is a new string which is formed from the original string by deleting some of the characters without disturbing the relative positions of the remaining characters. 
For example, "AGH" is a subsequence of "ABCDEFGH" while "AHG" is not.

Input

First line of input contains an integer T which is equal to the number of test cases. You are required to process all test cases. Each of next T lines contains a string s.

Output

Output consists of T lines. Ith line in the output corresponds to the number of distinct subsequences of ith input string. Since, this number could be very large, you need to output ans%1000000007 where ans is the number of distinct subsequences.

Example

Input:
3
AAA
ABCDEFG
CODECRAFT


Output:
4
128
496

Constraints and Limits

T ≤ 100, length(S) ≤ 100000
All input strings shall contain only uppercase letters.

不难看出, AAA的所有相异子字符串为: “ ”, "A", “AA”, "AAA"共有四个。 当字符串S的所有的字符均不同的时候, 我们假设S的长度为n, 那么distinct subsequence 的个数为
2^n, 例如S= ABC, S的subsequence的个数为2^3, 即共有8个。 当时当S中的有相同的字符出现了至少2次的时候, 说明个数小于 2^n。
sol:

It's a classic dynamic programming problem.

Let:

dp[i] = number of distinct subsequences ending with a[i]
sum[i] = dp[1] + dp[2] + ... + dp[i]. So sum[n] will be your answer.
last[i] = last position of character i in the given string.

A null string has one subsequence, so dp[0] = 1.

read a
n = strlen(a)
for i = 1 to n
  dp[i] = sum[i - 1] - sum[last[a[i]] - 1]
  sum[i] = sum[i - 1] + dp[i]
  last[a[i]] = i

return sum[n]

Explanation

dp[i] = sum[i - 1] - sum[last[a[i]] - 1]

Initially, we assume we can append a[i] to all subsequences ending on previous characters(即sum[i-1]), but this might violate the condition that the counted subsequences need to be distinct. Remember that last[a[i]] gives us the last position a[i] appeared on until now. The only subsequences we overcount are those that the previous a[i] was appended to, so we subtract those(sum[last[a[i]] - 1]).

sum[i] = sum[i - 1] + dp[i]
last[a[i]] = i

Update these values as per their definition.

If your indexing starts from 0, use a[i - 1] wherever I used a[i]. Also remember to wrap your computations in a mod function if you're going to submit code. This should be implemented like this:

mod(x) = (x % m + m) % m

In order to correctly handle negative values in some languages (such as C/C++).

另外:

There exists an easier solution to this problem.

The idea is : If all character of the string are distinct, total number of subsequences is 2^n. Now, if we find any character that have already occurred before, we should consider it's last occurrence only(otherwise sequence won't be distinct). So we have to subtract the number of subsequences due to it's previous occurrence.

My implementation is like this:

read s
dp[0] = 1
len = strlen(s)
for (i = 1; i <= len; i++) 
{
    dp[i] = (dp[i - 1] * 2)
    if (last[s[i]] != 0) dp[i] = (dp[i] - dp[last[s[i]] - 1])
    last[s[i]] = i

SELECT DATE_FORMAT(first_order_time, '%Y-%m') AS 月份, COUNT(user_phone) AS 总订单, COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-01' THEN user_phone END) AS '2025年1月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-02' THEN user_phone END) AS '2025年2月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-03' THEN user_phone END) AS '2025年3月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-04' THEN user_phone END) AS '2025年4月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-05' THEN user_phone END) AS '2025年5月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-06' THEN user_phone END) AS '2025年6月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-07' THEN user_phone END) AS '2025年7月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-08' THEN user_phone END) AS '2025年8月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-09' THEN user_phone END) AS '2025年9月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-10' THEN user_phone END) AS '2025年10月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-11' THEN user_phone END) AS '2025年11月(成交)', COUNT(DISTINCT CASE WHEN DATE_FORMAT(final_delivery_time, '%Y-%m') = '2025-12' THEN user_phone END) AS '2025年12月(成交)' FROM ( SELECT o.user_phone, MIN(o.order_create_time) AS first_order_time, MAX(CASE WHEN o.order_status IN ('4','41','42','5','8','9','10','12','13','14','15','121','122','131') THEN o.order_delivery_time END) AS final_delivery_time FROM orders o LEFT JOIN orders_info_source s ON s.order_id = o.order_id LEFT JOIN source c ON c.identify = s.source WHERE o.user_phone NOT IN ( '13828732621','13530358933','18358889349','13713666003','18038032144','18565399454', '18683409156','18254701866','18907432501','13430561693','14776231050','13543336115', '18973513561','18735590366','18823462817','18682291432','18503022713','19129425190', '17681043696','13544004613','13728731424','15989379809','19854594695','15989379809', '13590480601','14797635860','16602837041','13536880980','16602837041','17633834697', '13544004613','18318452072','13138615524','13078687152','15119332972','17724600370', '13787964520','18681078176','16607486252','18566230353','18824797256','15219857297' ) AND o.platform = 1 AND o.goods_id <> 6233 AND o.order_type <> '3' AND o.order_create_time BETWEEN '2025-01-01 00:00' AND '2025-12-31 23:59' AND o.order_status IN ('4','41','42','5','6','7','71','8','9','10','12','13','14','15','121','122','131') -- AND c.label LIKE 'A2%' and (o.deposit_free <> 1 and (o.add_pay_periods <> 0 or nt.order_id is null)) -- 非直发 GROUP BY o.user_phone ) AS user_orders GROUP BY 月份 ORDER BY 月份; 按月份为分组,左边列是下单的日期,但是下单之后不一定成交,要查询出该订单最后一次下单日期并且成交的,如1月下单的客户有可能是2月才第二次下单成交,有可能是3月再次下单成交的,需要查出第一次下单,最后在哪个月份成交的订单数据 字段:o.order_create_time下单日期,o.order_delivery_time发货日期,o.order_id订单号,o.order_status订单状态, 优化sql写一下完整sql
最新发布
06-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值