题解:P11952 [科大国创杯初中组 2023] 行走
图床挂了,重传。
这场的简单题……你谷评紫真就全员小学生?
考虑不操作,就是求网格图最短路。
断边,做两遍最短路。
操作情况下,即正反求一遍,发现最短路形如暴力把网格断开处
这里手动分讨一下就可以
注意到转移是后缀形式,两个后缀最小就好。
场上是可以新开数组的,洛谷这里卡了一下,直接把
远古代码,码风较为“优美”。
#include <bits/stdc++.h>
using namespace std;
const int N=5005,Q=100005;
typedef long long ll1;
ll1 n,q,B;
ll1 f[N][N],f1[N][N],ans;
ll1 ea[N][N],eb[N][N];
// ll1 sufmn1[N][N],sufmn2[N][N];
unsigned long long seed;
void xorshift64() {
seed ^= seed << 13;
seed ^= seed >> 7;
seed ^= seed << 17;
}
const ll1 inf=1e16+8;
void init(){
f[1][1]=0;
f1[n][n]=0;
for(int i=2;i<=n;i++)f[1][i]=f[1][i-1]+ea[1][i-1];
for(int j=2;j<=n;j++)f[j][1]=f[j-1][1]+eb[j-1][1];
for(int i=n-1;i>=1;i--)f1[n][i]=f1[n][i+1]+ea[n][i];
for(int j=n-1;j>=1;j--)f1[j][n]=f1[j+1][n]+eb[j][n];
for(int i=2;i<=n;i++)for(int j=2;j<=n;j++)f[i][j]=min(f[i][j-1]+ea[i][j-1],f[i-1][j]+eb[i-1][j]);
for(int i=0;i<=n+1;i++)
for(int j=0;j<=n+1;j++){
if(i<1||j<1||j>=n||i>n)ea[i][j]=inf;
if(i<1||j<1||j>n||i>=n)eb[i][j]=inf;
}
for(int i=n-1;i>=1;i--)for(int j=n-1;j>=1;j--)f1[i][j]=min(f1[i][j+1]+ea[i][j],f1[i+1][j]+eb[i][j]);
for(int j=1;j<=n;j++)
for(int i=n;i>=1;i--)
ea[i][j]=min(ea[i+1][j],f[i][j]+f1[i][j+1]+ea[i][j]);
for(int i=1;i<=n;i++)
for(int j=n;j>=1;j--)
eb[i][j]=min(eb[i][j+1],f[i][j]+f1[i+1][j]+eb[i][j]);
}
int main(){
// freopen("1.in","r",stdin);
scanf("%lld%lld",&n,&q);
scanf("%llu%llu",&seed,&B);
for (int i = 1; i <= n; i++) {
for (int j = 1; j != n; j++) {
xorshift64();
ea[i][j] = seed & ((1 << B) - 1);
}
}
for(int i = 1; i != n; i++) {
for(int j = 1; j <= n; j++) {
xorshift64();
eb[i][j] = seed & ((1 << B) - 1);
}
}
int i,j,qx1,qy1,qx2,qy2;
init();
while(q--){
scanf("%d%d%d%d",&qx1,&qy1,&qx2,&qy2);
ans=inf;
if(qx1==qx2){
j=qy1;
ans=min(ans,ea[qx1+1][j]);
i=qx1-1;
ans=min(ans,eb[i][qy1+1]);
}else{
j=qy1-1;
ans=min(ans,ea[qx1+1][j]);
i=qx1;
ans=min(ans,eb[i][qy1+1]);
}
printf("%lld\n",ans);
}
}