jzoj1115 GT考试

Description

申准备报名参加GT考试,准考证号为n位数X1X2X3…Xn-1Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数字A1A2A3…Am-1Am(0<=Ai<=9)有m位,不出现是指X1X2X3…Xn-1Xn 中没有恰好一段等于A1A2A3…Am-1Am。A1和X1可以为0。
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果。
Input
第一行输入n,m,K,接下来一行输入m 位的数。
Output
模K取余的结果。
对100%的数据满足n<=10^9,m<=20,K<=1000;

题解

首先我们考虑最直接的递推
Fi,j 表示两边分别匹配到i位置,j位置

fi,j=fi1,kcank,j

其中, can[k,j] 就是当匹配了k个位置的时候,再在原数后任意加一位数有多少方案能匹配j位
注意:在矩阵中表示,两个下标顺序要小心。

can数组怎么求呢?
你猜
假设现在情况是这样的,已经匹配了J位。
然后呢,我们在A后面加一位
这里写图片描述
这个匹配位数的转移一定是这样的

fi,j>fi+1,k

那么这里的K能等于多少呢?
其实就是求X的黑色部分的相等前后缀(包括本身与空串)且这个前缀的后一位=?,那么K就等于这个前缀的长度+1了。
这一步可以枚举下一个数(0~9),用KMP中的求相等前后缀的思想解决

KMP能吃吗

然后就矩阵乘法+快速幂优化

被坑了的地方

扫了一遍题目,然后一位是X的后k位和A的后k位匹配。。 MD,想了半天然后拍断大腿

code

type
    matrix=array[0..20,0..20] of longint;
var
    fri,ans:matrix;
    max,a:array[0..20] of longint;
    n,m,mo,k,i,j:longint;
function mamult(a,b:matrix):matrix;
var i,j,k,q:longint;
begin
    fillchar(mamult,sizeof(mamult),0);
    for k:=0 to m-1 do
    for i:=0 to m-1 do
        for j:=0 to m-1 do
        begin
            mamult[k,i]:=(mamult[k,i]+a[k,j]*b[j,i]) mod mo;
        end;
end;

function qsm(m:longint;t:matrix):matrix;
var i:longint;
    tt:matrix;
begin
    dec(m);
    tt:=t;
    while m>0 do
    begin
        if m and 1=1 then
            t:=mamult(t,tt);
        tt:=mamult(tt,tt);
        m:=m shr 1;
    end;
    exit(t);
end;

procedure init;
var c:char;
    l:longint;
begin
    assign(input,'1115.in'); reset(input);
    readln(n,m,mo);
    for i:=1 to m do
    begin
        read(c);
        a[i]:=ord(c)-48;
    end;

    for i:=2 to m do
    begin
        l:=max[i-1];
        while (l<>0)and(a[l+1]<>a[i]) do l:=max[l];
        if a[l+1]=a[i] then max[i]:=l+1;
    end;

    for i:=0 to m-1 do
        for j:=0 to 9 do
        begin
            l:=i;
            while (l<>0)and(a[l+1]<>j) do l:=max[l];
            if a[l+1]=j then inc(l);
            if (l<m) then inc(fri[l,i]);
        end;

end;

begin
    init();
    fri:=qsm(n,fri);
    for i:=0 to m do inc(k,fri[i,0]);
    writeln(k mod mo);
end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值