JZOJ 4673. 4504. 5635. 【NOI2018模拟4.7】LCS

Description

Description

Input

Input

Output

Output

Sample Input

【样例输入1】

3 3
aaa

【样例输入2】

3 3
aab

【样例输入3】

1 2
a

【样例输入4】

10 9
abacadefgh

Sample Output

【样例输出1】

6

【样例输出2】

11

【样例输出3】

1

【样例输出4】

789

Data Constraint

Data Constraint

Solution

  • 考虑用算重的方案数-重复的方案数。

  • 我们可以把原串以相同字符为一块分成很多块,因为同一块内字符都有同样的作用。

  • 像 aaabbacc 这样的字符串,就变成 aaa|bb|a|cc ,每一块内都统计一次答案。

  • 一个字符被挖去后,有 n 个位置可以选,每个位置又有 m 种字符可以填。

  • 但是每个位置又有一种字符会重复,如 abc ,把 c 挖去,则无论填 a 的左边还是右边都一样。

  • 这样 n 个位置都重复一遍 ,于是每个块都贡献 nmn 的答案。

  • 但是这样还是会算重!

  • 比如说字符串 abab ,把第三个字符 a 挖去后是 abb ,接到后边是 abba 。

  • 而把第四个字符 b 挖去后是 aba ,接到倒数第二个位置是 abba 。

  • 它们是一样的!我们发现如果是隔位相同的也会算重一次,

  • 而且隔的位数 k 每多一,它就与前面每个字符都重复一遍——它满足等差数列的形式。

  • 即第一个字符重复 0 次,第二个字符重复 1 次,第三个字符重复 2 次……

  • 那么这个长度为 k 的隔位相同的串就重复了 k(k1)2 次,减去即可。

  • 时间复杂度 O(N)

Code

#include<cstdio>
using namespace std;
typedef long long LL;
int n,m,k=1;
LL ans=1;
char s[100005];
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s",s+1);
    for(int i=2;i<=n;i++) ans+=s[i]!=s[i-1];
    ans*=(LL)n*m-n;
    for(int i=2;i<=n;i++)
        if(k==1) k+=s[i]!=s[i-1]; else
            if(s[i]==s[i-2]) k++; else
            {
                ans-=(LL)k*(k-1)>>1;
                k=(s[i]!=s[i-1])+1;
            }
    ans-=(LL)k*(k-1)>>1;
    printf("%lld",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值