【bzoj4386】[POI2015]Wycieczki【矩阵快速幂】【倍增】

vjudge题目传送门
luogu题目传送门
题解
首先,我们考虑如何统计所有边权都是1的经过x条边的路径总数。很简单,构造转移矩阵我们只需要相邻的两个点u->v,(u,v)++,再设一个计数器代表路径总数,(u,计数器)++,最后再 (计数器,计数器)=1。初始矩阵就是(1,1)=(1,2)…=(1,n)=1。然后快速幂。
但是如果权值有2,3呢?蒟蒻从题解上get到一个很妙的想法:把每个点搞成3个,u1,u2,u3。
对于边(u,v)边权为1:
u1->v1
边权为2:
u1->u2->v1
边权为3:
u1->u2->u3->v1
现在明白是什么意思了吧!
这样每条边的权值都是1了。
现在我们可以很方便地求出经过x条边的路径总数。
接下来,有一个想法是二分。但是这里有一个更妙的想法:倍增。我们二进制拆分,从高位到低位统计答案。细节自己想一想吧。
生命中的第一个bzoj rank1,第二个luogu rank1!嗨森~
倒是没怎么卡。就是矩阵乘法改了一下枚举的顺序,0就直接跳过。纪念一下。
这里写图片描述
这里写图片描述
233 wyc大佬莫名乱入
代码

#include<cstdio>
#include<cstring>
typedef long long ll;
const int N=125;
int n,m,u,v,d,t;
ll k,s,bg[N][N],base[N][N],tmp[N][N],now[N][N],mul[64][N][N];
bool flag;
void times(ll a[][N],ll b[][N],ll c[][N]){
    flag=true;
    memset(tmp,0,sizeof(tmp));
    for(int i=1;i<=3*n+1;i++){
        for(int l=1;l<=3*n+1;l++){
            if(!a[i][l]){
                continue;
            }
            for(register int j=1;j<=3*n+1;j++){
                tmp[i][j]+=a[i][l]*b[l][j];
            }
            if(i==1&&tmp[i][3*n+1]>=k){
                flag=false;
            }
        }
    }
    for(int i=1;i<=3*n+1;i++){
        for(int j=1;j<=3*n+1;j++){
            c[i][j]=tmp[i][j];
        }
    }
}
int main(){
    scanf("%d%d%lld",&n,&m,&k);
    for(int i=1;i<=n;i++){
        bg[1][i]=1;
        base[i][i+n]=1;
        base[i+n][i+2*n]=1;
    }
    while(m--){
        scanf("%d%d%d",&u,&v,&d);
        base[u+(d-1)*n][v]++;
        base[u+(d-1)*n][3*n+1]++;
    }
    base[3*n+1][3*n+1]=1;
    memcpy(mul[0],base,sizeof(base));
    for(;t<=63;t++){
        if(t){
            times(mul[t-1],mul[t-1],mul[t]);
        }
        times(bg,mul[t],now);
        if(!flag||now[1][3*n+1]>=k){
            break;
        }
    }
    t--;
    if(t==63&&now[1][3*n+1]<k){
        puts("-1");
        return 0;
    }
    for(int i=t;i>=0;i--){
        times(bg,mul[i],now);
        if(flag&&now[1][3*n+1]<k){
            s+=(1LL<<i);
            memcpy(bg,now,sizeof(now));
        }
    }
    printf("%lld\n",s+1);
    return 0;
}
posted @ 2018-07-04 17:23  ez_2016gdgzoi471  阅读(138)  评论(0编辑  收藏  举报