Codeforces 852B 矩阵乘法优化DP

原题链接:http://codeforces.com/problemset/problem/852/B

大致题意:有 L 层的城市群,每层城市群由n个不相连的城市构成,上一层的第 I 个城市到下一层的第 J 个城市的代价是B[ J ],从最顶层的入口到第1层城市I的代价为 A[ I ],从最底层的城市K到出口的代价为C[ k ] ,问有多少种方法使得从入口到出口的代价和为M的倍数(答案对1e9+7取余数)。( L<=10^5 , N<=10^6 , M<=100)

DP方程显然可以定为 f[ i ] [ j ]表示到了第 i 层花销对M取余为J的方法数,然后可以发现每层之间的转移方程是不会变的,于是就可以用矩阵乘法+快速幂来快速进行DP转移。

小细节就是到了第N-1层时就不能继续用原来的转移方程了,因为最后一层到出口的代价不一样了,最后特殊处理一下就好了。

代码:

#include <bits/stdc++.h>

using namespace std;
inline void read(int &x){
    char ch;
    bool flag=false;
    for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
    for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    x=flag?-x:x;
}

inline void read(long long &x){
    char ch;
    bool flag=false;
    for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
    for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    x=flag?-x:x;
}


inline void write(int x){
    static const int maxlen=100;
    static char s[maxlen];
        if (x<0) {   putchar('-'); x=-x;}
    if(!x){ putchar('0'); return; }
    int len=0; for(;x;x/=10) s[len++]=x % 10+'0';
    for(int i=len-1;i>=0;--i) putchar(s[i]);
}

const int MAXN = 1100000;

int tot,l,lim;
int v[ MAXN ];
long long cnt[ 200 ];

struct Matrix{
int n,m;
long long a[120][120];
Matrix (){
    memset( a, 0 ,sizeof( a )) ;
    n=0,m=0;
}

void out(){
    puts("");
    for (int i=0;i<n;i++)
    {
        for (int j=0;j<m;j++)
            printf("%d ",a[i][j]);
        puts("");
    }
    puts("");
}

void init(){
    memset(cnt , 0 ,sizeof( cnt ));
    for (int i = 1;i<=tot;i++)
        {
            int x;
            read(x);
            x=x%lim;
            v[i]=x;
            cnt[x]++;
        }
    n=lim;  m=lim;
    for (int i=0;i<lim;i++)
        for (int j=0;j<lim;j++)
            a[ i ][ (i+j)%lim  ]=cnt[j];
    }
};

const long long P=1000000007ll;

Matrix operator * ( Matrix A, Matrix B ){
Matrix C;
C.n=A.n; C.m=B.m;
for (int i=0;i<A.n;i++)
    for (int j=0;j<A.m;j++)
        for (int k=0;k<B.m;k++)
            C.a[i][k]= ( C.a[i][k] + 1ll*A.a[i][j] * B.a[j][k]%P )%P;
return C;
}

Matrix st,mid,ORG;


Matrix get_pow( Matrix A ,int x){
if (x==0)
    return ORG;
Matrix tmp=get_pow( A ,x/2);
if ( x%2==0 )
    return tmp*tmp;
else
    return tmp*tmp*A;
}

int main(){
    read(tot); read(l); read(lim);
    ORG.n=lim;ORG.m=lim;
    for (int i = 0;i<lim;i++)
        ORG.a[i][i]=1;

    st.n=1; st.m=lim;
    for (int i = 1;i<=tot;i++)
        {
            int x;
            read(x);
            x=x%lim;
            st.a[0][x]++;
        }

    mid.init();
    memset(cnt,0,sizeof(cnt));
    for (int i = 1;i<=tot;i++)
        {
            int x;
            read(x);
            cnt[ ( x + v[i] ) % lim ] ++;
        }

    mid=get_pow(mid,l-2);
    //mid.out();
    st=st*mid;
    int ans=0;
    for (int i=0;i<lim;i++)
        if ( cnt [ i ] )
            ans= ( ans + 1ll*st.a[0][ ( lim-i)%lim ]*cnt[ i ]%P )%P;
    printf("%d\n",ans);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/u012602144/article/details/77970529
今日推荐