Loading

洛谷P2334

不知道写点啥好了,把昨天晚上做的屑题放上来好了。

不到 15 mins 口胡了个很傻逼的方程,然后玄学改了改数据范围就过了。

看到转移,每次只能走一格,只有三个方向可以走,所以考虑枚举走到当前格子的状态。

由于有个什么周期限制,再考虑枚举走到当前格子的时间。

\(f_{i,j}\) 表示在时间 \(i\) 走到了格子 \(j\)

显然有转移方程式:

\[f_{i,j}=\min\{f_{i-1,j},f_{i-1,j-1},f_{i-1,j+1}\}+v_{i \bmod t_j,j} \]

其中 \(t_j\) 表示格子 \(j\) 的周期,\(v_{i\bmod t_j,j}\) 表示在这个时间这个格子收到的伤害。特别的,当 \(i\bmod t_j=0\) 时要变成 \(v_{t_j,j}\)

这式子第一眼看上去很 naive 对吗?我一开始也这么觉得。

当然,由于并没有规定要在什么时间内走到终点,所以我们枚举这个时间。

看到 \(n\le 1000\),然后我猜测最差情况下,每个格子的每种周期攻击都承受时,可以到 \(10000\) 步。

当然也没有什么依据,但是比较保险,而且这个范围完全可以过。

signed main(){
  n=read();
  memset(f,INF,sizeof f);
  for(int i=0;i<=n+10000;i++) f[i][0]=0;
  for(int i=1,x;i<=n;i++){
    d[i]=read();
    for(int j=1;j<=d[i];j++)
      c[i][j]=read();
  }
  
  for(int i=1;i<=n+10000;i++){
    for(int j=1,tim;j<=min(n+1,i);j++){
      if(d[j]) tim=i%d[j];
      else tim=11;
      if(tim==0) tim=d[j];
      f[i][j]=min(f[i][j],f[i-1][j]+c[j][tim]);
      f[i][j]=min(f[i][j],f[i-1][j-1]+c[j][tim]);
      f[i][j]=min(f[i][j],f[i-1][j+1]+c[j][tim]);
    }
  }
  int ans=INF;
  for(int i=n+1;i<=n+10000;i++)
    ans=min(ans,f[i][n+1]);
  cout<<ans<<endl;
  return 0;
}

写的比较难看,毕竟本来对这个式子没啥信心,不过还可以。

posted @ 2021-07-02 22:06  KnightL  阅读(49)  评论(1编辑  收藏  举报