JZOJ5686. 【GDOI2018Day1模拟4.24】狮鹫旅行

Description

狮鹫是联盟的主要交通工具,在艾泽拉斯的土地上散布着n个狮鹫站点,有m条有向的飞行线路,也就是构成了一张n个点m条边的有向图。
这m条线路被分成了c种等级,对于其中的第i种等级,只有声望达到了w i 才能乘坐狮鹫飞过这条线路。
小C现在在暴风城(1号点),他要赶到暗月马戏团(n号点)参加他学长的电音表演。作为一个喜欢藏锋的健美先生,初始时他声望为0。但他实在是太健美了,以至于他每乘坐一次狮鹫(即经过一条边)就能使他的声望 +1 。
为了更好地藏锋,小C不会通过其他方法来提升声望。小C不喜欢步行,也不会开传送门,所以他不会通过除乘坐狮鹫以外的其他方法来到达另一个站点。现在他想知道是否能到达,如果能,他还想知道他最少要经过多少条边才能到达.

Input

从文件griffin.in中读入数据.
第一行三个整数n,m,c.
接下来m行,每行三个整数u,v,lv,表示有一条u到v的线路,等级为lv. 接下来一行c个整数,第i个表示w i .

Output

输出到文件griffin.out中.
若不能到达输出Impossible。
否则输出一个整数表示他最少要经过的边数。

Sample Input

输入1:
3 2 2
1 2 1
2 3 2
0 2

输入2:
3 3 2
1 2 1
2 1 1
2 3 2
0 2

Sample Output

输出1:
Impossible

输出2:
4

Data Constraint

对于所有数据,有2≤n≤180,1≤c≤50,0≤m≤4×10^4 ,0≤wi≤wi+1≤10^9 .
可 能 有 重 边 或 自 环.
• subtask1(17%), c = 1.
• subtask2(24%), w i ≤ 10^3 .
• subtask3(27%), n ≤ 40.
• subtask4(32%), 没有特殊的约定.

题解

注意观察就可以发现,在 [ w i , w i + 1 ) 的时候,整张图可以走的边是相同的,
所以,整张图的边改变就只有c次。
将每个时刻可以到达的点的0/1状态看成以行向量,
中间的转移矩阵就是图中有哪些边。
每走也不就是乘上一次中间这个转移矩阵,
而这个转移矩阵在某些连续的时刻是不变的,
那么就可以有快速幂来处理。

具体做法:从小到大枚举边的等级,
将符合当前等级的边加入转移矩阵,
类似倍增的样子,求出这个矩阵的2的次幂次方,
先判断在到达下一个等级之前是否能到达n(为了方便处理,提前加入一条等级最低n的自环)。
如果不可以,就直接跳到下一个等级,
否则就说明在这个等级的某个时刻就已经到达n了。
从大到小枚举这个矩阵的2的次幂次方,
如果行向量乘上这个矩阵没有到达n,就将其乘上,并记录答案。
最后答案就+1好了,这个过程很类似倍增求lca。
算一下时间复杂度 O ( n 3 l o g 2 w c ) 好像有点大,
那么就用bitset优化。

code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<bitset> 
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
    int w;
    for(ch=G();(ch<'0' || ch>'9') && ch!='-';ch=G());
    if(ch=='-')w=-1,ch=G();else w=1;
    for(n=0;'0'<=ch && ch<='9';ch=G())n=(n<<1)+(n<<3)+ch-48;
    n=n*w;
}

const int N=203;

struct node
{
    int x,y,v;
}a[N*N];

int n,m,c,w[N],ans,pos,z[33],t;
bool pd;
bitset<N>f[33][N],A[N],B,p,q;

bool cmp(node a,node b)
{
    return a.v<b.v;
}

void mul(int x)
{
    for(register int i=1;i<=n;i++)
            f[x][i].reset();
    for(register int i=1;i<=n;i++)
        for(register int j=1;j<=n;j++)
            if(f[x-1][i][j])f[x][i]|=f[x-1][j];
}

void mul1(int x)
{
    for(int i=1;i<=n;i++)
        B[i]=q[i];
    q.reset();
    for(register int i=1;i<=n;i++)
        if(B[i])q|=f[x][i];
}

int main()
{
    freopen("griffin.in","r",stdin);
    freopen("griffin.out","w",stdout);
    z[0]=1;
    for(int i=1;i<33;i++)
        z[i]=z[i-1]<<1;
    read(n);read(m);read(c);
    for(int i=1;i<=m;i++)
        read(a[i].x),read(a[i].y),read(a[i].v);
    for(int i=1;i<=c;i++)
        read(w[i]);
    m++;a[m].x=a[m].y=n;
    sort(a+1,a+1+m,cmp);
    p[pos=1]=1;w[c+1]=w[c]+m+n;
    for(int k=0;k<=c;k++)
    {
        for(;a[pos].v==k;pos++)f[0][a[pos].x][a[pos].y]=1;
        t=w[k+1]-w[k];
        for(int i=1;z[i]<=t;i++)mul(i);

        q=p;
        for(int i=0;z[i]<=t;i++)
            if(t&z[i])mul1(i);
        if(q[n])
        {
            pd=1;
            for(int i=29;i>=0;i--)
                if(z[i]<=t)
                {
                    q=p;
                    mul1(i);
                    if(!q[n])
                    {
                        p=q;
                        ans|=z[i];
                    }
                }
            ans+=w[k];
            break;
        }
        else p=q;
    }
    if(pd)printf("%d\n",ans+1);else puts("Impossible");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/80108871
今日推荐