【题解】「abc171F」Strivore

题意

求出在一个字符串 s s s 中插入 n n n 个小写字母,有多少不同的结果。 n ≤ 1 0 6 n\leq 10^6 n106

solution:

神仙计数题。本题可以等价转化为,有多少长度为 n + m n+m n+m 的字符串存在子序列串 s s s 。为了避免算重,我们规定如果有相同字符,则取序列中的最后一个 。

例如:字符串 abbcddc 的子序列 bc,从字符串的结尾往开头找,c 找到字符串末尾,b 找到字符串第三位。不难发现,对于一个给定的字符串所对应的唯一子序列是确定的。

那么我么就可以考虑枚举开头位置 1 ≤ i ≤ m + 1 1\leq i \leq m+1 1im+1 i i i 前面的每一个数都没有限制,总共 2 6 i − 1 26^{i-1} 26i1 种可能。对于后面 n + m − i n+m-i n+mi 个数,首先选出 m − 1 m-1 m1 个数确定子序列在字符串中的位置;对于剩下 n − i + 1 n-i+1 ni+1 个不在子序列中的数,为了满足定义,我们知道不能和它后继的子序列中的字符一样,所以总共 2 5 n − i + 1 25^{n-i+1} 25ni+1 种可能。

如图,可以发现的确有 25 25 25 种可能。

在这里插入图片描述

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

其实这道题我最开始的想法是考虑 26 26 26 种颜色,也能保证字符串长得不一样,但是似乎很难算答案。

#include<bits/stdc++.h> #define ll long long using namespace std; const int mx=2e6+5; const int mod=1e9+7; int n,m; ll res,fac[mx],inv[mx]; //相同的字符 x ,取序列中的最后一个 ll fpow(ll x,ll y) { ll mul=1; for(;y;y>>=1) { if(y&1) mul=mul*x%mod; x=x*x%mod; } return mul; } ll C(ll x,ll y) { return fac[x]*inv[x-y]%mod*inv[y]%mod; } ll A(ll x,ll y) { return fac[x]*inv[y]%mod; } ll G(ll x,ll y) { return C(x+y-1,y-1); } char s[mx]; int main() { // freopen("data.in","r",stdin); scanf("%d%s",&m,s+1),n=strlen(s+1); fac[0]=1; for(int i=1;i<=2000000;i++) fac[i]=fac[i-1]*i%mod; inv[2000000]=fpow(fac[2000000],mod-2); for(int i=2000000;i>=1;i--) { inv[i-1]=inv[i]*i%mod; } for(int i=1;i<=m+1;i++) { ll turn1=fpow(26,i-1),turn2=C(n+m-i,n-1)*fpow(25,n+m-i-(n-1))%mod; res=(res+turn1*turn2%mod)%mod; } cout<<res; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530330.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示