codeforces#191_div2_C Magic Five 矩阵快速幂

来源:互联网 发布:怎么打开php文件 编辑:程序博客网 时间:2024/04/29 10:42

题目地址:点这里

额,思考的方式还是在纸上,举几个简单的例子。找找规律。

首先,只有一个循环节的时候,就是sigma pow(2,p[i])    其中p[i] 为s[p[i]] =='0'||'5';

然后有k个循环节的时候,找到了递推方程。f[n]=f[n-1]+2^(Length*(n-1))*T;

其中T是一个循环节对应的方法数。

f[n]可以理解为,仅使用前n个循环节对应的方法数,那么对最后一个循环节,要么不用(f[n-1] ) ,要么用,前面n-1 循环节,对应(n-1)*Length 这么多元素,都可以取或者不取。

于是就是一个等比数列求和。

但是不能再分母上取模。

所以设计了一个矩阵,使用矩阵快速幂来解决。

注意:凡是两个int相乘的地方就要取mod。

代码:

#include<iostream>using namespace std;typedef  long long  inta;const int mod=1000000007;int p[100005];inta quick_mod(inta a,int n){    inta ans=1;     while(n>0)     {        if(n&1)        {            ans=(ans*a)%mod;        }         a=(a*a)%mod;         n>>=1;     }        return ans;}struct Matrix {        inta p[2][2];    Matrix()    {        for(int i=0;i<2;i++)            for(int j=0;j<2;j++)                p[i][j]=(i==j)?1:0;            }};Matrix  multi(Matrix A,Matrix B){    Matrix ans;        for(int i=0;i<2;i++)        for(int j=0;j<2;j++)        {            inta sum=0;            for(int k=0;k<2;k++)            {                sum=(sum+(A.p[i][k]*B.p[k][j])%mod)%mod;            }                        ans.p[i][j]=sum;        }        return  ans;}Matrix quick_mod(Matrix A,int n){    Matrix ans;        while(n)    {        if(n&1)        {            ans=multi(ans, A);        }                A=multi(A, A);        n>>=1;    }        return ans;}int main(){       string s;    cin>>s;    inta L=s.length();        inta Base=quick_mod(2,L);        int k;    cin>>k;        inta T=0;        int c=0;    for(int i=0;i<s.length();i++)    {        if(s[i]=='0'||s[i]=='5')  p[c++]=i;    }        for(int i=0;i<c;i++)    {        T=(T+quick_mod(2, p[i]))%mod;    }        Matrix A;    A.p[0][0]=1;    A.p[0][1]=0;    A.p[1][0]=1;    A.p[1][1]=Base;        A=quick_mod(A, k-1);        inta TB=(T*Base)%mod;        cout<<((T*A.p[0][0])%mod+(TB*A.p[1][0])%mod)%mod<<endl;    }

其实本题的答案就是T*(2^0+2^(L)+2^(2L)+...+2^(k-1)L)

就是枚举最后一位出现在第几个循环节,然后前面的长度任取。

等比数列求和的类似于快速幂的写法

改了一下,简洁很多。

代码:

#include<iostream>using namespace std;typedef  long long  inta;const int mod=1000000007;int p[100005];inta quick_mod(inta a,int n){    inta ans=1;     while(n>0)     {        if(n&1)        {            ans=(ans*a)%mod;        }         a=(a*a)%mod;         n>>=1;     }        return ans;}inta calc(inta A,int n)  // 等比数列求和{    if(n==0)  return  1;    if(n==1)  return (1+A)%mod;        if(n%2==0)    {        inta x=calc(A,n/2);        inta d=quick_mod(A, n/2);        return ((d*(x-1))%mod+x)%mod;    }        else    {        inta x=calc(A,(n-1)/2);        inta d=quick_mod(A, (n+1)/2);        return ((d*x)%mod+x)%mod;    }  }int main(){        string s;    cin>>s;    inta L=s.length();        inta Base=quick_mod(2,L);        int k;    cin>>k;           inta T=0;        int c=0;    for(int i=0;i<s.length();i++)    {        if(s[i]=='0'||s[i]=='5')  p[c++]=i;    }        for(int i=0;i<c;i++)    {        T=(T+quick_mod(2, p[i]))%mod;    }        cout<<(calc(Base,k-1)*T)%mod<<endl;        return 0;        }




0 0