求斐波那契数列
模板
cpp
struct Matrix{
int a[N][N];
Matrix(){
memset(a,0,sizeof a);
}
Matrix operator * (const Matrix &b)const{
Matrix res;
for(int i=1;i<N;i++){
for(int j=1;j<N;j++){
for(int k=1;k<N;k++)(res.a[i][j]+=a[i][k]*b.a[k][j])%=mod;
}
}
return res;
}
};
Matrix qpow(Matrix a,int b){
Matrix ans;
for(int i=1;i<N;i++)ans.a[i][i]=1;
for(;b;b>>=1){
if(b&1)ans=ans*a;
a=a*a;
}
return ans;
}
void solve(){
int n,k;
cin>>n>>k;
Matrix a;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)cin>>a.a[i][j];
}
a=qpow(a,k);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)cout<<a.a[i][j]<<" \n"[j==n];
}
}矩阵快速幂求解经过n条边的最短路
- 邻接矩阵,表示经过条路径的最短路
cpp
struct Matrix{
int m[210][210];
int x,y;
Matrix(int _x=0,int _y=0):x(_x),y(_y){memset(m,0x3f,sizeof m);}
Matrix operator*(const Matrix &t)const{
Matrix res(x,t.y);
for(int k=1;k<=y;k++){
for(int i=1;i<=x;i++){
for(int j=1;j<=t.y;j++){
res.m[i][j]=min(res.m[i][j],m[i][k]+t.m[k][j]);
}
}
}
return res;
};
};
Matrix qpow(Matrix a,int b){
Matrix res(a.x,a.y);
for(int i=1;i<=a.x;i++)res.m[i][i]=0;
while(b){
if(b&1)res=res*a;
a=a*a;
b>>=1;
}
return res;
}
void solve(){
int n,t,s,e;
cin>>n>>t>>s>>e;
map<int,int> mp;
auto get=[&](int x){
if(mp.count(x))return mp[x];
return mp[x]=mp.size()+1;
};
s=get(s),e=get(e);
Matrix ans;
for(int i=1;i<=t;i++){
int u,v,w;
cin>>w>>u>>v;
u=get(u),v=get(v);
ans.m[u][v]=ans.m[v][u]=min(ans.m[u][v],w);
}
ans.x=ans.y=mp.size();
ans=qpow(ans,n);
cout<<ans.m[s][e]<<"\n";
}P6772 [NOI2020] 美食家
题目描述
坐落在 Bzeroth 大陆上的精灵王国击退地灾军团的入侵后,经过十余年的休养生息,重新成为了一片欣欣向荣的乐土,吸引着八方游客。小 W 是一位游历过世界各地的著名美食家,现在也慕名来到了精灵王国。
精灵王国共有 座城市,城市从 到 编号,其中城市 的美食能为小 W 提供 的愉悦值。精灵王国的城市通过 条单向道路连接,道路从 到 编号,其中道路 的起点为城市 ,终点为城市 ,沿它通行需要花费 天。也就是说,若小 W 在第 天从城市 沿道路 通行,那么他会在第 天到达城市 。
小 W 计划在精灵王国进行一场为期 天的旅行,更具体地:他会在第 天从城市 出发,经过 天的旅行,最终在恰好第 天回到城市 结束旅行。由于小 W 是一位美食家,每当他到达一座城市时(包括第 天和第 天的城市 ),他都会品尝该城市的美食并获得其所提供的愉悦值,若小 W 多次到达同一座城市,他将获得多次愉悦值。注意旅行途中小 W 不能在任何城市停留,即当他到达一座城市且还未结束旅行时,他当天必须立即从该城市出发前往其他城市。

对于上图,小 W 一种为期 天的可行旅游方案为 :
- 第 天,小 W 从城市 开始旅行,获得愉悦值 并向城市 出发。
- 第 天,小 W 到达城市 ,获得愉悦值 并向城市 出发。
- 第 天,小 W 到达城市 ,获得愉悦值 并向城市 出发。
- 第 天,小 W 到达城市 ,获得愉悦值 并向城市 出发。
- 第 天,小 W 到达城市 ,获得愉悦值 并向城市 出发。
- 第 天,小 W 到达城市 ,获得愉悦值 并结束旅行。
- 小 W 在该旅行中获得的愉悦值之和为 。
此外,精灵王国会在不同的时间举办 次美食节。具体来说,第 次美食节将于第 天在城市 举办,若小 W 第 天时恰好在城市 ,那么他在品尝城市 的美食时会额外得到 的愉悦值。现在小 W 想请作为精灵王国接待使者的你帮他算出,他在旅行中能获得的愉悦值之和的最大值。
对于所有测试点:
,,,。
,,,。
思路:
- 很大,需要使用矩阵快速幂,但是矩阵快速幂需要满足边权为
- 因为边权最多为,考虑拆点,对于变成连边
- 那么如果没有个派对,那么答案怎么算
- 初始有一个
1*5n的矩阵代表到达的价值 - 那么还有一个
5n*5n的矩阵,代表到的最大价值 - 答案就是
- 如果有派队,那么根据时间走,到达对应的时间,对应的点加上贡献
- 复杂度,会超时
- 考虑对二进制分组预处理,复杂度为
- 那么每次询问时,一次矩阵乘法是
1*5n和5n*5n的矩阵相乘,复杂度为,可以通过
cpp
struct Matrix{
vector<vector<int>> m;
int x,y;
Matrix(int _x=0,int _y=0):x(_x),y(_y){m.assign(_x+1,vector<int>(_y+1,-INF));}
Matrix operator*(const Matrix &t)const{
Matrix res(x,t.y);
for(int k=1;k<=y;k++){
for(int i=1;i<=x;i++){
for(int j=1;j<=t.y;j++){
res.m[i][j]=max(res.m[i][j],m[i][k]+t.m[k][j]);
}
}
}
return res;
};
void print(){
for(int i=1;i<=x;i++){
for(int j=1;j<=y;j++){
cout<<m[i][j]<<" ";
}
cout<<"\n";
}
}
};
Matrix qpow(Matrix a,int b){
Matrix res=a;
b--;
while(b){
if(b&1)res=res*a;
a=a*a;
b>>=1;
}
return res;
}
int getid(int x,int y){
return (x-1)*5+y;
}
void solve(){
int n,m,T,k;
cin>>n>>m>>T>>k;
vector<Matrix> mat(32);
mat[0]=Matrix(5*n,5*n);
vector<int> c(n+1);
for(int i=1;i<=n;i++)cin>>c[i];
for(int i=1;i<=n;i++){
for(int j=1;j<5;j++)mat[0].m[getid(i,j)][getid(i,j+1)]=0;
}
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
mat[0].m[getid(u,w)][getid(v,1)]=max(mat[0].m[getid(u,w)][getid(v,1)],c[v]);
}
vector<array<int,3>> dot(k);
for(auto &[t,x,y]:dot)cin>>t>>x>>y;
ranges::sort(dot);
Matrix ans(1,5*n);
ans.m[1][getid(1,1)]=c[1];
for(int i=1;i<32;i++)mat[i]=mat[i-1]*mat[i-1];
int lst=0;
for(auto &[t,x,y]:dot){
int r=t-lst;
for(int i=0;i<32;i++){
if(r>>i&1)ans=ans*mat[i];
}
ans.m[1][getid(x,1)]+=y;
lst=t;
}
if(lst<T){
int r=T-lst;
for(int i=0;i<32;i++){
if(r>>i&1)ans=ans*mat[i];
}
}
cout<<(ans.m[1][getid(1,1)]<0?-1:ans.m[1][getid(1,1)])<<"\n";
}CF576D Flights for Regular Customers
一张有向图,个点条边,从走到
只有走过条边,才能走第条
问最少要走多少条边,或者无法到达
思路:
- 定义一个矩阵,表示可以从到
- 是一个邻接矩阵
- 对排序
- 那么可以用更新在走条边前的
- 然后对可达点跑全源bfs,更新答案为
- 复杂度:,超时
- 考虑矩阵只有01,公式可以bitset优化
- 复杂度为:
cpp
struct Matrix{
vector<bitset<151>> m;
int x,y;
Matrix(int _x=0,int _y=0):x(_x),y(_y){m.assign(_x+1,bitset<151>());}
Matrix operator*(const Matrix &t)const{
Matrix res(x,t.y);
for(int k=1;k<=y;k++){
for(int i=1;i<=x;i++){
if(m[i][k])res.m[i]|=t.m[k];
}
}
return res;
};
};
Matrix qpow(Matrix a,int b){
Matrix res(a.x,a.y);
for(int i=1;i<=a.x;i++){
res.m[i][i]=1;
}
while(b){
if(b&1)res=res*a;
a=a*a;
b>>=1;
}
return res;
}
void solve(){
int n,m;
cin>>n>>m;
Matrix A(1,n),G(n,n);
A.m[1][1]=1;
vector<array<int,3>> e(m);
vector<int> dis(n+1);
for(auto &[d,u,v]:e)cin>>u>>v>>d;
ranges::sort(e);
int T=0;
auto bfs=[&](){
fill(dis.begin(),dis.end(),INF);
queue<int> q;
for(int i=1;i<=n;i++){
if(A.m[1][i])q.push(i),dis[i]=0;
}
while(!q.empty()){
auto u=q.front();
q.pop();
for(int i=1;i<=n;i++){
if(G.m[u][i]&&dis[i]==INF){
dis[i]=dis[u]+1;
q.push(i);
}
}
}
};
int ans=INF;
for(int i=0;i<m;i++){
auto [d,u,v]=e[i];
int r=d-T;
A=A*qpow(G,r);
G.m[u][v]=1;
if(i==m-1||T!=d){
bfs();
ans=min(ans,dis[n]+d);
}
T=d;
}
if(ans==INF)cout<<"Impossible\n";
else cout<<ans<<"\n";
}