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异或的二 ...
随机推荐
- Java中多个异常的捕获顺序(多个catch)
import java.io.IOException; public class ExceptionTryCatchTest { public void doSomething() throws IO ...
- MongoDB探索之路(三)——索引
1.索引介绍 2.创建语句 1)基础索引 在字段age 上创建索引,1(升序);-1(降序):db.users.ensureIndex({age:1}) _id 是创建表的时候自动创建的索引,此索引是 ...
- [整理]C 内核源代码-学习资料
GNU C gnu项目:http://www.gnu.org/software/software.html ftp:http://ftp.gnu.org/gnu/ 托管:http://savannah ...
- [转]Linux联网问题
一.Kali联网问题 首先ifconfig,可以看到没有正在工作的网卡,只有localhost 然后ifconfig -a,可以看到eth0这块网卡并没有离家出走,只是罢工了而已 打开/etc/net ...
- python垃圾回收三之标记清除
#第一组循环引用# a = [1,2] b = [3,4] a.append(b) b.append(a) del a ## #第二组循环引用# c = [4,5] d = [5,6] c.appen ...
- 阿里云OSS 中文名称地址不对
oss中将该中文名称重命名.再输入一次
- 【转载】maven pom详解(2)
setting.xml主要用于配置maven的运行环境等一系列通用的属性,是全局级别的配置文件:而pom.xml主要描述了项目的maven坐标,依赖关系,开发者需要遵循的规则,缺陷管理系统,组织和li ...
- yum安装失败:ublic key for **.rpm is not installed
yum install mysql-server --nogpgcheck package_need_to_install
- elasticsearch安装ik分词器(极速版)
简介:下面讲有我已经打包并且编辑过的zip包,你可以在下面下载即可. 1.下载zip包.elasticsearch-analysis-ik-1.8.0.jar下面有附件链接[ik-安装包.zip],下 ...
- centos7系统下安装配置jdk、tomcat教程
JDK安装与配置 1.下载linux版本的jdk,我下的版本是jdk6.0,下载rpm版本的. 可通过百度搜索文件名:jdk-6u45-linux-x64-rpm.bin下载 也可通过oracle官网 ...