码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 576D. Flights for Regular Customers(倍增+floyd+bitset优化)

时间:2017-12-14 22:54:48      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:eve   one   possible   close   set   printf   style   view   --   

  这破题调了我一天...错了一大堆细节T T

  首先显然可以将边权先排序,然后逐个加进图中。

  加进图后,倍增跑跑看能不能到达n,不能的话加新的边继续跑。

  倍增的时候要预处理出h[i]表示转移矩阵的2^0~i的或和,转移是h[i]=h[i-1]*h[i-1]。

  注意两个矩阵包含0~i和0~j相乘的时候,得到的矩阵是0~i*j的,而两个矩阵包含0~i和0~j或起来的时候,得到的矩阵是j~i+j的。

  倍增的时候因为必须答案单调,所以当前的值必须或上之前的值。

技术分享图片
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<bitset>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=160, inf=1e9+160;
struct mtx{bitset<maxn>mp[maxn]; mtx(){for(int i=0;i<maxn;i++) mp[i].reset();}}tmp, tmp2, f, base, h[35];
struct poi{int x, y, dis;}a[maxn];
int n, m;
mtx operator *(mtx a, mtx b)
{
    mtx c;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    if(a.mp[i][j]) c.mp[i]|=b.mp[j];
    return c;
}
mtx operator |(mtx a, mtx b)
{
    mtx c; 
    for(int i=1;i<=n;i++)
    c.mp[i]|=a.mp[i]|b.mp[i];
    return c;
}
inline void power(int b)
{
    if(b<=0) return;
    for(;b;b>>=1, tmp=tmp*tmp)
    if(b&1) f=f*tmp;
}
inline bool cmp(poi a, poi b){return a.dis<b.dis;}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++) scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].dis);
    sort(a+1, a+1+m, cmp); a[m+1].dis=inf;
    if(a[1].dis) return puts("Impossible"), 0;
    for(int i=1;i<=n;i++) f.mp[i][i]=1;
    for(int i=1;i<=m;i++)
    {
        tmp=base; power(a[i].dis-a[i-1].dis);
        base.mp[a[i].x][a[i].y]=1;
        int up=log2(a[i+1].dis-a[i].dis);
        h[0]=base; for(int j=1;j<=n;j++) h[0].mp[j][j]=h[0].mp[j][j]|1;
        mtx tmpx; for(int j=1;j<=n;j++) tmpx.mp[j][j]=1;
        if(a[i+1].dis-a[i].dis & 1) tmpx=tmpx|(tmpx*h[0]);
        for(int j=1;j<=up;j++) 
        {
            h[j]=h[j-1]*h[j-1];
            if(a[i+1].dis-a[i].dis & (1<<j)) tmpx=tmpx|(tmpx*h[j]);
        }
        tmpx=f*tmpx; 
        if(!tmpx.mp[1][n]) continue;
        mtx tmp1=f; int ans=0;
        for(int j=up;j>=0;j--)
        if(a[i].dis+ans+(1<<j)<=a[i+1].dis)
        {
            tmp2=tmp1; tmp2=tmp2*h[j];
            if(tmp2.mp[1][n]) continue;
            ans+=(1<<j); tmp1=tmp2;
        }
        return printf("%d\n", a[i].dis+ans+1), 0;
    }
    puts("Impossible");
}
View Code

 

Codeforces 576D. Flights for Regular Customers(倍增+floyd+bitset优化)

标签:eve   one   possible   close   set   printf   style   view   --   

原文地址:http://www.cnblogs.com/Sakits/p/8040256.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!