题意:

给一个\(n\)点\(m\)边的连通图 每个边有一个权值\(d\) 当且仅当当前走过的步数\(\ge d\)时 才可以走这条边 问从节点\(1\)到节点\(n\)的最短路

好神的一道题 直接写做法喽

首先我们对边按\(d_i\)由小到大排序 设\(f_i\)表示加上\(1\sim i-1\)的所有边走\(d_i\)次后各点间的联通情况 \(G\)表示只连\(1\sim i-1\)的边的邻接矩阵 这些我们可以用一个\(01\)邻接矩阵来存储 则有

\(f_i=f_{i-1}*G^{d_i-d_{i-1}}\)

这很明显是一个矩阵快速幂的过程

之后只需要判断\(1\)与\(n\)之间是否联通 不连通就连下一条边继续判断 否则在当前的范围内二分判断

这样的复杂度还是不够优 我们发现矩阵相乘的过程可以压位后来做 于是将一个矩阵的状态压成\(n\)个\(bitset<n>\) 这样就可过了

我的代码没有压位 而是直接暴力相乘 不过做了点小优化居然就过了~

#include<bits/stdc++.h>
using namespace std;
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define pa pair<int,int>
#define mod 1000000007
#define ll long long
#define mk make_pair
#define pb push_back
#define fi fisrt
#define se second
#define cl(x) memset(x,0,sizeof x)
#ifdef Devil_Gary
#define bug(x) cout<<(#x)<<" "<<(x)<<endl
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define bug(x)
#define debug(...)
#endif
const int INF = 0x7fffffff;
const int N=155;
/*
char *TT,*mo,but[(1<<15)+2];
#define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/
inline int read(){
int x=0,rev=0,ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return rev?-x:x;
}
struct data{
int u,v,t;
bool operator < (const data&ch){
return t<ch.t;
}
}e[N];
int cnt,n,m,tmp[N],sz,bin[32]={1};
struct matrix{
bool v[N][N];
matrix operator * (const matrix&b){
matrix c;cl(c.v);
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++){
if(!v[j][i]) continue;
for(int k=1;k<=n;k++)
c.v[j][k]|=v[j][i]&&b.v[i][k];
}
return c;
}
}g[N],G,f[N][32];
bool judge(int x){
int pos=upper_bound(tmp+1,tmp+sz+1,x)-tmp-1,ret=x-tmp[pos];
// debug("x=%d pos=%d\n",x,pos);
matrix d=g[pos];
// bug(d.v[1][n]);
for(int k=0;k<=30;k++){
if(bin[k]&ret){
d=d*f[pos][k];
}
}
return d.v[1][n];
}
int main(){
#ifdef Devil_Gary
freopen("in.txt","r",stdin);
#endif
n=read(),m=read();
for(int i=1;i<=30;i++) bin[i]=bin[i-1]<<1;
for(int i=1;i<=n;i++) g[1].v[i][i]=1;
for(int i=1;i<=m;i++){
e[++cnt].u=read(),e[cnt].v=read(),e[i].t=read();
// if(!e[i].t) g[1].v[e[i].u][e[i].v]=1;
tmp[++sz]=e[i].t;
}
e[++cnt].u=n,e[cnt].v=n,e[cnt].t=0,tmp[++sz]=0;
sort(tmp+1,tmp+sz+1);
sz=unique(tmp+1,tmp+sz+1)-tmp-1;
sort(e+1,e+cnt+1);
for(int i=1,j=1;i<=sz;i++){
for(;e[j].t<=tmp[i]&&j<=cnt;j++){
G.v[e[j].u][e[j].v]=1;
}
f[i][0]=G;
for(int k=1;k<=30;k++) f[i][k]=f[i][k-1]*f[i][k-1];
if(i==sz) continue;
int ret=tmp[i+1]-tmp[i];
g[i+1]=g[i];
for(int k=0;k<=30;k++){
if(bin[k]&ret){
g[i+1]=g[i+1]*f[i][k];
}
}
}
int l=0,r=1e9+155;
while(l<r){
int mid=l+r>>1;
if(judge(mid)) r=mid;
else l=mid+1;
}
/* debug("l=%d rr=%d\n",l,tmp[sz]+n+1);*/
if(l==1e9+155) return puts("Impossible"),0;
return !printf("%d\n",l);
}

下面这份是压位的做法 我直接粘来的

#include <bits/stdc++.h>
using namespace std;
int n, m;
const int N = 160;
struct edge
{
int a, b, c;
} E[N];
struct mat
{
bitset <N> d[N];
} O, I, P, Q;
int comp(edge x, edge y)
{
return x.c < y.c;
}
mat operator * (mat a, mat b)
{
mat c;
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= n; ++ j)
if (a.d[i][j])
c.d[i] |= b.d[j];
return c;
}
mat operator ^ (mat a, int b)
{
mat c = I;
for (; b; b >>= 1, a = a * a)
if (b & 1) c = c * a;
return c;
}
void print(mat a)
{
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= n; ++ j)
cerr << a.d[i][j] << " ";
cerr << endl;
}
}
int res;
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; ++ i)
I.d[i][i] = 1;
for (int i = 1; i <= m; ++ i)
cin >> E[i].a >> E[i].b >> E[i].c;
sort(E + 1, E + m + 1, comp);
E[m + 1].c = E[m].c + n + 5;
P = I; Q.d[n][n] = 1;
for (int i = 1; i <= m + 1; ++ i)
{
cout<<i<<endl;
mat tmp = P * (Q ^ (E[i].c - E[i - 1].c));
if (!tmp.d[1][n])
{
Q.d[E[i].a][E[i].b] = 1;
P = tmp;
continue;
}
res = E[i - 1].c;
while (!P.d[1][n]) P = P * Q, res ++;
cout << res << endl;
return 0;
}
cout << "Impossible" << endl;
}

Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP的更多相关文章

  1. Codeforces 576D Flights for Regular Customers(矩阵加速DP)

    题目链接  Flights for Regular Customers 首先按照$d$的大小升序排序 然后分成$m$个时刻,每条路径一次处理过来. $can[i][j]$表示当前时刻$i$能否走到$j ...

  2. Codeforces 576D Flights for Regular Customers (图论、矩阵乘法、Bitset)

    题目链接 http://codeforces.com/contest/576/problem/D 题解 把边按\(t_i\)从小到大排序后枚举\(i\), 求出按前\((i-1)\)条边走\(t_i\ ...

  3. Codeforces 576D - Flights for Regular Customers(bitset 优化广义矩阵乘法)

    题面传送门 题意: 有一张 \(n\) 个点 \(m\) 条边的有向图,你初始在 \(1\) 号点,边上有边权 \(c_i\) 表示只有当你经过至少 \(c_i\) 条边的时候你才能经过第 \(i\) ...

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

    这破题调了我一天...错了一大堆细节T T 首先显然可以将边权先排序,然后逐个加进图中. 加进图后,倍增跑跑看能不能到达n,不能的话加新的边继续跑. 倍增的时候要预处理出h[i]表示转移矩阵的2^0~ ...

  5. Codeforces 989E A Trance of Nightfall 矩阵快速幂+DP

    题意:二维平面上右一点集$S$,共$n$个元素,开始位于平面上任意点$P$,$P$不一定属于$S$,每次操作为选一条至少包含$S$中两个元素和当前位置$P$的直线,每条直线选取概率相同,同一直线上每个 ...

  6. CF576D Flights for Regular Customers 矩阵乘法 + Bitset优化

    %%%cxhscst2's blog Codeforces 576D Flights for Regular Customers(矩阵加速DP) 代码非常优美 + 简洁,学习到了 Code: #inc ...

  7. (中等) CF 576D Flights for Regular Customers (#319 Div1 D题),矩阵快速幂。

    In the country there are exactly n cities numbered with positive integers from 1 to n. In each city ...

  8. Codeforces Round #536 (Div. 2) F 矩阵快速幂 + bsgs(新坑) + exgcd(新坑) + 欧拉降幂

    https://codeforces.com/contest/1106/problem/F 题意 数列公式为\(f_i=(f^{b_1}_{i-1}*f^{b_2}_{i-2}*...*f^{b_k} ...

  9. codeforces 691E 矩阵快速幂+dp

    传送门:https://codeforces.com/contest/691/problem/E 题意:给定长度为n的序列,从序列中选择k个数(可以重复选择),使得得到的排列满足xi与xi+1异或的二 ...

随机推荐

  1. 程序员与HR博弈之:有城府的表达你的兴趣爱好

    “面试”这个过程说简单其实也能很简单.譬如急需招某种技能的单位会因为你拥有某方面的经验或特长立马录取你,哪怕你其他方面表现的很“烂”. 从广义上来讲,很多公司尤其是大中型公司的招聘,并不是因为急缺某岗 ...

  2. Caffe 碎碎念

    Window Data Layer window data layer 的数据是存在硬盘上的图片, 需要在一个txt里指定用于训练或测试的图片以及bounding box, bounding box ...

  3. CentOS 无法通过 yum 安装新版 nodejs 解决办法(安装的还是老版的)

    官网安装说明:CentOS 安装 nodejs 第一步: curl --silent --location https://rpm.nodesource.com/setup_10.x | sudo b ...

  4. list(列表)操作【五】

    L表示从左边(头部)开始插与弹出,R表示从右边(尾部)开始插与弹出. 一.概述:      在Redis中,List类型是按照插入顺序排序的字符串链表.和数据结构中的普通链表一样,我们可以在其头部(l ...

  5. linux常用运维命令【转】

    自己的小网站跑在阿里云的ECS上面,偶尔也去分析分析自己网站服务器日志,看看网站的访问量.看看有没有黑阔搞破坏!于是收集,整理一些服务器日志分析命令,大家可以试试! 1.查看有多少个IP访问: awk ...

  6. CodeSmith的基础模版类(CodeSmith help中的内容)

    基础模版类类型描述: Batch      OutputFileCodeTemplate  模版通过继承此类能够在生成过程中把他们的输出保存到文件中 ScriptError    在脚本执行中出现一个 ...

  7. linux:根据名称杀死进程

    参考网址:https://www.cnblogs.com/foohack/p/5359985.html pkill -f "process_name_pattern"

  8. C++资源之不完全导引

    1,前言 无数次听到“我要开始学习C++!”的呐喊,无数次听到“C++太复杂了,我真的学不会”的无奈.Stan Lippman先生曾在<C++ Primer>一书中指出“C++是最为难学的 ...

  9. CSS渐变之CSS3 gradient在Firefox3.6下的使用

    一.引子 Firefox3.6包含了许多CSS的改进,本文将向您展示如果使用CSS渐变. 如果你正在运行的Firefox 3.6的最新测试版,你应该看看我们的互动演示,并查看相应的代码.使用单选按钮来 ...

  10. 2018年湘潭大学程序设计竞赛 F - maze

    把点抽出来 跑个最短路就好啦. #include<bits/stdc++.h> #define LL long long #define pii pair<int,int> # ...