[SDOI2009]HH去散步 动态规划+矩阵乘法优化

[SDOI2009]

  • 就是求从S到T有多少条长度为t的路径,满足当前走过的路不能是上一次走过的

40pts

  • 无脑爆搜?
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int mod=45989;
const int N=1e5;
struct node{int y,n;}e[N];
int lin[N],v[N],len=1,ans=0,n,m,t,x,y,a,b;
void read(int x,int y)
{e[++len].y=y,e[len].n=lin[x],lin[x]=len;}
void dfs(int x,int d,int pre){
    if(d>t)return;
    if(x==b&&d==t){
        ans++;
        if(ans>=mod)ans-=mod;
        return;
    }
    for(int i=lin[x];i;i=e[i].n){
        int y=e[i].y;
        if((i^1)==pre)continue;
        dfs(y,d+1,i);
    }
}
int main()
{
    scanf("%d%d%d%d%d",&n,&m,&t,&a,&b);
    rep(i,1,m){
        scanf("%d%d",&x,&y); 
        read(x,y),read(y,x);
    }
    dfs(a,0,0);
    cout<<ans;
    return 0;
}
  • 动态规划
  • f[i][j]表示目前已经走了i步,上一次走过的边是j的方案数
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int mod=45989;
const int N=1e6;
struct node{int y,n;}e[N];
int lin[N],len=1,ans=0,n,m,t,x,y,a,b;
void read(int x,int y)
{e[++len].y=y,e[len].n=lin[x],lin[x]=len;}
map<int,map<int,int> > f;
int main()
{
    scanf("%d%d%d%d%d",&n,&m,&t,&a,&b);
    rep(i,1,m){
        scanf("%d%d",&x,&y); 
        read(x,y),read(y,x);
    }
    for(int i=lin[a];i;i=e[i].n)f[1][i]=1;
    rep(i,1,t){
        rep(j,2,len){
            if(e[j].y==b&&i==t)ans=(ans+f[i][j])%mod;
            for(int k=lin[e[j].y];k;k=e[k].n){
                int y=e[k].y;
                if((k^1)!=j)
                f[i+1][k]=(f[i+1][k]+f[i][j])%mod;			
            }
        }
    }
    cout<<ans;
    return 0;
}

100pts

  • 考虑动态规划的转移可以用矩阵乘法优化,构造一个合法的转移矩阵每次矩阵快速幂即可
  • 本地运行的时候爆栈了,手动开栈 
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int mod=45989;
const int N=300;
struct node{int y,n;}E[N];
struct mat{int m[N][N];};

int lin[N],len=0,ans=0,n,m,t,x,y,s,ed;
mat a,b,e;

void read(int x,int y)
{E[++len].y=y,E[len].n=lin[x],lin[x]=len;}

int o(int x){return ((x%2)?(x+1):(x-1));}

mat mul(mat x,mat y)
{
    mat c;rep(i,1,len)rep(j,1,len)c.m[i][j]=0;
    rep(i,1,len)rep(j,1,len)rep(k,1,len)
    c.m[i][j]=(c.m[i][j]+x.m[i][k]*y.m[k][j]%mod)%mod;
    return c;
}
mat pow(mat x,int y){mat ans=e;for(;y;y>>=1,x=mul(x,x))if(y&1)ans=mul(ans,x);return ans;}
int main()
{
    scanf("%d%d%d%d%d",&n,&m,&t,&s,&ed);
    rep(i,1,m){
        scanf("%d%d",&x,&y); 
        read(x,y),read(y,x);
    }
    
    for(int i=lin[s];i;i=E[i].n)a.m[1][i]=1;
    rep(i,1,len){
        for(int j=lin[E[i].y];j;j=E[j].n){
            if(i==o(j))continue;
            b.m[i][j]=1;
        }
    }
    rep(i,1,len)e.m[i][i]=1;

    b=pow(b,t-1);
    a=mul(a,b);

    rep(i,1,len)if(E[i].y==ed)ans=(ans+a.m[1][i])%mod;
    cout<<ans;
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/strangeDDDF/article/details/88135568