Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP
题意:
给一个\(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的更多相关文章
- Codeforces 576D Flights for Regular Customers(矩阵加速DP)
题目链接 Flights for Regular Customers 首先按照$d$的大小升序排序 然后分成$m$个时刻,每条路径一次处理过来. $can[i][j]$表示当前时刻$i$能否走到$j ...
- Codeforces 576D Flights for Regular Customers (图论、矩阵乘法、Bitset)
题目链接 http://codeforces.com/contest/576/problem/D 题解 把边按\(t_i\)从小到大排序后枚举\(i\), 求出按前\((i-1)\)条边走\(t_i\ ...
- Codeforces 576D - Flights for Regular Customers(bitset 优化广义矩阵乘法)
题面传送门 题意: 有一张 \(n\) 个点 \(m\) 条边的有向图,你初始在 \(1\) 号点,边上有边权 \(c_i\) 表示只有当你经过至少 \(c_i\) 条边的时候你才能经过第 \(i\) ...
- Codeforces 576D. Flights for Regular Customers(倍增floyd+bitset)
这破题调了我一天...错了一大堆细节T T 首先显然可以将边权先排序,然后逐个加进图中. 加进图后,倍增跑跑看能不能到达n,不能的话加新的边继续跑. 倍增的时候要预处理出h[i]表示转移矩阵的2^0~ ...
- Codeforces 989E A Trance of Nightfall 矩阵快速幂+DP
题意:二维平面上右一点集$S$,共$n$个元素,开始位于平面上任意点$P$,$P$不一定属于$S$,每次操作为选一条至少包含$S$中两个元素和当前位置$P$的直线,每条直线选取概率相同,同一直线上每个 ...
- CF576D Flights for Regular Customers 矩阵乘法 + Bitset优化
%%%cxhscst2's blog Codeforces 576D Flights for Regular Customers(矩阵加速DP) 代码非常优美 + 简洁,学习到了 Code: #inc ...
- (中等) 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 ...
- 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} ...
- codeforces 691E 矩阵快速幂+dp
传送门:https://codeforces.com/contest/691/problem/E 题意:给定长度为n的序列,从序列中选择k个数(可以重复选择),使得得到的排列满足xi与xi+1异或的二 ...
随机推荐
- angular.module()参数问题
var app = angular.module('myApp', []); 第二个参数是依赖的模块,因为这里不需要依赖其它模块,因此为空,但是[]不能省略.
- Spark记录-Scala数组
Scala提供了一种数据结构叫作数组,数组是一种存储了相同类型元素的固定大小顺序集合.数组用于存储数据集合,但将数组视为相同类型变量的集合通常更为有用. 可以声明一个数组变量,例如:numbers,使 ...
- SHELL (4) —— 变量的数值计算实践
摘自:Oldboy Linux运维——SHELL编程实战 利用(())双括号进行比较及判断: [root@yeebian ~]# echo $((3<8)) 1 #1表示真. [root@yee ...
- JavaScript编写风格指南 (三)
七(七):严格模式 // 严格模式应当仅限在函数内部使用,千万不要在全局使用 //不好的写法:全局使用严格模式"user strict"; function doSomething ...
- CSUST 1506 ZZ的计算器 模拟题
题目描述:实现一个计算器,可以进行任意步的整数以内的加减乘除运算,运算符号只有+.-.*./,求出结果. 解题报告:一个可以说麻烦的模拟题,我们可以这样,输入以字符串的形式输入,然后将输入先做一遍预处 ...
- Servlet笔记10--Session
Web编程中的Session: 代码示例: package com.bjpowernode.javaweb.servlet; import java.io.IOException; import ja ...
- crontab每10秒钟执行一次
1.使用sleep 在crontab中加入 * * * * * sleep 10; /bin/date >>/tmp/date.txt* * * * * sleep 20; /bin/da ...
- tar.gz tar.bz2的解压命令
.tar.gz 格式解压为 tar -zxvf xx.tar.gz .tar.bz2 格式解压为 tar -jxvf xx.tar.b ...
- 解决阿里云安骑士漏洞警告:wordpress WPImageEditorImagick 指令注入漏洞
解决:wordpress WPImageEditorImagick 指令注入漏洞 前些天在阿里云服务器上安装了wordpress,阿里云提示有wordpress WP_Image_Editor_Ima ...
- 证书(Certificate)与描述文件(Provisioning Profiles)
在使用脚本xcodebuild自动打包的时候,会用到签名证书和描述文件,我在编译的时候搞了好长时间才搞明白,下面介绍如何得到正确配置. 证书:证书是用来给应用程序签名的,只有经过签名的应用程序才能保证 ...