• P6772 [NOI2020] 美食家(矩阵快速幂)


    前言

    无能狂怒。
    见过甚至写过博客的trick,但就是想不起来了。

    解析

    做法1

    f t , x f_{t,x} ft,x 表示 t 时刻在 x 的最大价值。
    直接转移即可,时间复杂度 O ( T ( n + m ) ) O(T(n+m)) O(T(n+m)),期望得分 40 分。
    结合无脑转圈的 A 性质,可得 50 分。

    做法2

    数据范围把矩阵快速幂写脸上了。
    每条边建出对应时间个点转移,时间复杂度 O ( ( 5 m ) 3 k log ⁡ T ) O((5m)^3k\log T) O((5m)3klogT),期望得分 65-75 分。

    做法3

    发现点比较少,边比较多,每条边都分裂节点很蠢。
    于是改成把每个点分裂成5个,时间复杂度 O ( ( 5 n ) 3 k log ⁡ T ) O((5n)^3k\log T) O((5n)3klogT)
    期望得分没变,乐。

    然后?然后就不会了!
    。。。
    回家种地吧

    正解

    预处理出转移矩阵 2 k 2^k 2k 次,节日之间只需要用行向量乘转移矩阵即可。
    时间复杂度 O ( ( 5 n ) 3 log ⁡ T + ( 5 n ) 2 k log ⁡ T ) O((5n)^3\log T+(5n)^2k\log T) O((5n)3logT+(5n)2klogT),期望得分 100 分。
    这个优化这篇博客写过了,然而就是没有想到,乐。
    这甚至根本不能叫优化,就是个写法。
    乐。
    跳出刻板思维!

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define ull unsigned ll
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    #define ok debug("OK\n")
    
    inline ll read() {
      ll x(0),f(1);char c=getchar();
      while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
      while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
      return x*f;
    }
    const int N=255;
    const int mod=998244353;
    const ll inf=-1e18;
    
    bool mem1;
    
    bool Flag=0;
    
    inline ll ksm(ll x,ll k){
      ll res(1);
      x%=mod;
      while(k){
        if(k&1) res=res*x%mod;
        x=x*x%mod;
        k>>=1;
      }
      return res;
    }
    
    int n,m,T,k;
    int tot;
    int id[N][6];
    
    struct matrix{
      int x,y;
      ll a[N][N];
      matrix(int X=0,int Y=0):x(X),y(Y){memset(a,-0x3f,sizeof(a));}
    }tr,mi[40],res;
    matrix operator * (const matrix &u,const matrix &v){
      matrix res(u.x,v.y);
      assert(u.y==v.x);
      for(int k=1;k<=u.y;k++){
        for(int i=1;i<=u.x;i++){
          ll tmp=u.a[i][k];
          for(int j=1;j<=v.y;j++){
    	res.a[i][j]=max(res.a[i][j],tmp+v.a[k][j]);
          }
        }
      }
      return res;
    }
    int c[N];
    struct node{
      int t,x,w;
      bool operator < (const node &oth)const{return t<oth.t;}
    }o[N];
    int num;
    
    bool mem2;
    signed main(){
      #ifndef ONLINE_JUDGE
      freopen("a.in","r",stdin);
      freopen("a.out","w",stdout);
      #endif
        
      n=read();m=read();T=read();k=read();
      memset(tr.a,-0x3f,sizeof(tr.a));
      tr.x=tr.y=n*5;
      for(int i=1;i<=n;i++){
        for(int j=1;j<=5;j++) id[i][j]=++tot;
        for(int j=1;j<=4;j++) tr.a[id[i][j]][id[i][j+1]]=0;
      }
      for(int i=1;i<=n;i++) c[i]=read();
      for(int i=1;i<=m;i++){
        int x=read(),y=read(),w=read();
        tr.a[id[x][w]][id[y][1]]=c[y];
      }
      for(int i=1;i<=k;i++){
        int t=read(),x=read(),w=read();
        o[++num]=(node){t,x,w};
      }
      o[++num]=(node){T,1,0};
      sort(o+1,o+1+num);
      mi[0]=tr;
      for(int i=1;i<=30;i++) mi[i]=mi[i-1]*mi[i-1];
      res.x=1;res.y=tot;
      memset(res.a,-0x3f,sizeof(res.a));
      res.a[1][id[1][1]]=c[1];
      int pre(0);
      for(int i=1;i<=num;i++){
        int d=o[i].t-pre;
        for(int k=30;k>=0;k--){
          if(d&(1<<k)) res=res*mi[k];
        }
        res.a[1][id[o[i].x][1]]+=o[i].w;
        pre=o[i].t;
      }
      if(res.a[1][id[1][1]]<0) puts("-1");
      else printf("%lld\n",res.a[1][id[1][1]]);
      return 0;
    }
    /*
    */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
  • 相关阅读:
    CSS:弹性布局(display:flex)
    「C++」深度分析C++中i++与++i的区别
    设计模式~解释器模式(Interpreter)-19
    React@16.x(40)路由v5.x(5)常见应用场景(2)- 实现类似 vue 的路由模式
    unity基础 常用的API及脚本模板
    Linux 命令(167)—— last 命令
    三、工厂方法模式
    【Git】解决Untracked Files Prevent Checkout的问题
    面试题目:手写一个LRU算法实现
    Java基础- 浅谈javac和javap
  • 原文地址:https://blog.csdn.net/BUG_Creater_jie/article/details/125493940