• Luogu P2151 [SDOI2009]HH去散步 矩乘加速DP


    思路:矩乘优化DP

    提交:3次(用了一个奇怪的东西导致常数过大)

    题解:

    如果可以走完正向边后又走反向边那就显然了,但是不能走,所以我们要将正反向边分别编号,区分正反向边。

    所以这道题的矩阵是以边的编号(边的邻接矩阵),而非点来DP的。

    具体地,记录每个边$w_i=(u_i,v_i)$和$w_{i^1}=(v_{i^1},u_{i^1})$,注意这个有向的。

    设起点为$s$,终点为$t$,我们的初始矩阵$S$是一根行向量,把所有的$w_i and u_i==s $设为$1$,表示$s$与$w_i$连通;

    然后转移矩阵$a$:若$v_i==u_j and i!=j xor 1$ ,即两条边相连,但不是互为正反向边,则在边的邻接矩阵中设为$1$。

    然后快速幂,并令$ans=S*a$

    最后求解答案时,统计所有$ans$中$w_i and v_i==t$ 的答案,即为最终的答案。

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define R register int
    using namespace std;
    //你弱,有什么资格休息
    #define ull unsigned long long
    #define ll long long
    #define pause (for(R i=1;i<=10000000000;++i))
    #define In freopen("NOIPAK++.in","r",stdin)
    #define Out freopen("out.out","w",stdout)
    namespace Fread {
    static char B[1<<15],*S=B,*D=B;
    #ifndef JACK
    #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++)
    #endif
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        if(ch==EOF) return EOF; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    } inline bool isempty(const char& ch) {return (ch<=36||ch>=127);}
    inline void gs(char* s) {
        register char ch; while(isempty(ch=getchar()));
        do *s++=ch; while(!isempty(ch=getchar()));
    }
    } using Fread::g; using Fread::gs;
    
    namespace Luitaryi {
    const int N=130,M=45989;
    int n,m,p,S,T,cnt=-1,x[N],y[N];
    int a[N][N],s[2][N],ans[2][N],anss;
    inline void mul(int a[][N],int b[][N]) { R tmp[N][N]; memset(tmp,0,sizeof(tmp));
        for(R i=0;i<=cnt;++i) for(R k=0;k<=cnt;++k) for(R j=0;j<=cnt;++j)    
            (tmp[i][j]+=1ll*a[i][k]*b[k][j]%M)%=M;
        memcpy(a,tmp,sizeof(tmp));
    }
    inline void qpow(int p) {
        R ret[N][N]; memset(ret,0,sizeof(ret));
        for(R i=0;i<=cnt;++i) ret[i][i]=1;
        for(;p;p>>=1,mul(a,a)) if(p&1) mul(ret,a);
        memcpy(a,ret,sizeof(ret));
    }
    inline void main() {
        n=g(),m=g(),p=g(),S=g(),T=g();
        for(R i=1;i<=m;++i) {
            R u=g(),v=g();
            x[++cnt]=u,y[cnt]=v;
            x[++cnt]=v,y[cnt]=u;
        } for(R i=0;i<=cnt;++i) for(R j=0;j<=cnt;++j) if(i!=(j^1)&&y[i]==x[j]) a[i][j]+=1;
        for(R i=0;i<=cnt;++i) if(x[i]==S) s[1][i]=1;
        qpow(p-1); for(R i=0;i<=cnt;++i) for(R j=0;j<=cnt;++j) (ans[1][j]+=1ll*s[1][i]*a[i][j]%M)%=M;
        for(R i=0;i<=cnt;++i) if(y[i]==T) (anss+=ans[1][i])%=M; printf("%d
    ",anss);
    }
    } 
    signed main() {
        Luitaryi::main();
    }

    2019.07.20

  • 相关阅读:
    Delphi DbgridEh实现鼠标拖动选中列,并使复选框选中
    什么是运行期包与设计期包
    组件事件大全
    sql: 查找约束
    delphi Ctrl+鼠标左键或者Find Declaration不能定位到源文件
    delphi7 编译的程序在win7下请求获得管理员权限的方法
    DELPHI中build和compile有什么区别?
    线程安全的单件模式(单例模式)
    [Selenium]通过Selenium实现在当前浏览器窗口点击一个图标之后,弹出另外一个窗口,关闭这个窗口,再回到原来的窗口进行操作
    两种读写配置文件的方案(app.config与web.config通用)
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11217473.html
Copyright © 2020-2023  润新知