不知道写点啥好了,把昨天晚上做的屑题放上来好了。
不到 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 mod t_j,j}
]
其中 (t_j) 表示格子 (j) 的周期,(v_{imod t_j,j}) 表示在这个时间这个格子收到的伤害。特别的,当 (imod t_j=0) 时要变成 (v_{t_j,j})。
这式子第一眼看上去很 naive 对吗?我一开始也这么觉得。
当然,由于并没有规定要在什么时间内走到终点,所以我们枚举这个时间。
看到 (nle 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;
}
写的比较难看,毕竟本来对这个式子没啥信心,不过还可以。