JZOJ 4812 【NOIP2016提高A组五校联考2】string

string

题目大意

给出一个长度为 n , 由小写英文字母组成的字符串 S ,求在所有由小写英文字母组成且长度为 n 且恰好有 k 位与 S 不同的字符串中,给定字符串 T 按照字典序排在第几位。
由于答案可能很大,模 109 + 7 输出。

数据范围

对于 100 %的数据, k <= n <= 105

题解

问题转化,求有多少个字符串的字典序小于 T 且有 k 位和 S 不同。
我们先枚举第一位,若第一位比 T1 小,则第 2 ~ n 位填什么字母进去都可以,用组合数求出可行方案。
若第一位等于 T2 ,则我们枚举第二位,
有两种情况,第一种:第二位比 T2 小,第 3 ~ n 位填什么都可以,一样用组合数求出方案数。
第二种第二位等于 T2 ,那么我们就枚举第三位,如此类推下去到最后,求出答案即可。

Code(Pascal)

const
    mo=1000000007;
var
    f25,jc,ny:array[0..100000] of int64;
    n,m,j,k,l,i:longint;
    ch:char;
    ans,kk,ff:int64;
    s,t:ansistring;
function ksm(o,k:int64):int64;
    begin
        ksm:=1;
        while k>0 do
        begin
            if k mod 2=1 then ksm:=ksm*o mod mo;
            k:=k div 2;
            o:=o*o mod mo;
        end;
    end;
begin
    readln(n,k);
    readln(s);
    readln(t);
    f25[0]:=1;
    for i:=1 to n do
    f25[i]:=(f25[i-1]*25) mod mo;
    jc[0]:=1;
    ny[0]:=1;
    jc[1]:=1;
    ny[1]:=1;
    for i:=2 to n do
    begin
        jc[i]:=(jc[i-1]*i) mod mo;
        ny[i]:=ksm(jc[i],mo-2);
    end;
    l:=0;
    for i:=1 to n do
    begin
        for ch:='a' to chr(ord(t[i])-1) do
        begin
            kk:=l;
            if ch<>s[i] then inc(kk);
            kk:=k-kk;
            ff:=n-i;
            if (kk>=0) and (ff>=kk) then 
            ans:=(ans+((jc[ff]*ny[ff-kk] mod mo)*ny[kk] mod mo)*f25[kk]) mod mo;
        end;
        if t[i]<>s[i] then inc(l);
        if l>k then break;
    end;
    writeln((ans+1) mod mo);
end.

你可能感兴趣的:(组合数)