欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Gym100025K

程序员文章站 2022-06-29 11:14:00
矩阵快速幂 设答案为f(i) 举个例子: 当i==2时,包含0的值有:10,20,30,40,50,60,70,80,90,100;0的个数为11,f(2)=11; i==3时;可以从i==2的情况递推, 第一步:i==2时的数据范围:1-100;在这100个数后面补0;补0后,这些数在1-1000 ......

矩阵快速幂

设答案为f(i)

举个例子:

i==2时,包含0的值有:10,20,30,40,50,60,70,80,90,100;0的个数为11,f(2)=11;

i==3时;可以从i==2的情况递推,

第一步:i==2时的数据范围:1-100;在这100个数后面补0;补0后,这些数在1-1000的范围之内,合法,0的个数增加了100个,也就是10^(i-1);

第二步:把i==2时包含0的有效值拿出来,在这些值后面补0,1,2,3,4,5,6,7,8,9;

比如70;补数之后就成了:700,701,702,703,704,705,706,707,708,709;这样70里面0的个数就被计算了10次。至于700里面由于后面补零增加的一个0,这个可以发现已经在第一步中计算过了。因此加上10*f(i-1);

但要知道100后面补数的话,1001,1003,1003,1004,1005,1006,1007,1008,1009都是不合法的。不合法的情况有9种,每种里面包含0的个数为(i-1)

因此递推式为f(i)=10*f(i-1)+10^(i-1)-9*(i-1);

接下来就可以愉快的矩阵快速幂了。

#include<bits/stdc++.h>
using namespace std;
int f[10];
#define ll long long
ll mod;
ll res[4][4];
ll ans[4];
void ans()
{
    ll tmp[4]={0};
    for(int i=0;i<4;++i)
    {
        for(int j=0;j<4;++j)
        {
            tmp[i]=(tmp[i]+res[i][j]*ans[j])%mod;;
        }
    }
    for(int i=0;i<4;++i)ans[i]=tmp[i];
}
void a()
{
    ll tmp[4][4]={0};
    for(int i=0;i<4;++i)
    {
        for(int j=0;j<4;++j)
        {
            for(int k=0;k<4;++k)tmp[i][j]=(tmp[i][j]+res[i][k]*res[k][j])%mod;
        }
    }
    for(int i=0;i<4;++i)for(int j=0;j<4;++j)res[i][j]=tmp[i][j];
}
void init(ll n)
{
    --n;
    res[0][0]=10%mod;res[0][1]=10%mod;res[0][2]=(-9%mod+mod)%mod;
    res[1][1]=10%mod;
    res[2][2]=res[2][3]=1;
    res[3][3]=1;
    for(int i=0;i<4;++i)ans[i]=1;
    while(n){
        if(n&1)ans();
        n>>=1;a();
    }
    cout<<ans[0]<<endl;
}
int main()
{
    /*
    f[1]=1;
    for(int i=2;i<=6;++i){
        f[i]=10*f[i-1]+pow(10,i-1)-9*(i-1);
        cout<<f[i]<<endl;
    }
    */
    freopen("zeroes.in","r",stdin);
    freopen("zeroes.out","w",stdout);
    ll k;
    cin>>k>>mod;
    if(mod==1)cout<<0<<endl;
    else init(k);
}

 

推荐阅读