思路
首先,這道題一定是個,因爲題中說一旦機器人走到頭了,就要立刻在其他任意的一個機器人工廠買。
一開始弄得是到了第個工廠,用了個時間,機器人已經走到頭了的最大金幣數,然後一想,似乎不需要前面這一個維度,(我要你有何用),反正下一次都可以在任意的地方幹嘛還要這樣嘛。
所以就用表示用了個時間,機器人已經走到頭了的最大金幣數,轉移公式就是:
就是在分鐘時從個工廠開始向後走個工廠路上可以得到的價值。
然後,就在想怎麼求這個奇怪的,呦吼,前綴和是個好東西,用前綴和表示,現在用了分鐘走到了個工廠所得到的金幣數,那麼,不就可以遞推求解了嗎?這裏要注意一下是個環,我習慣開頭了,改不掉。
所以,先用數組存下每條道路每個時間的金幣數
這個因爲我是從開始的,所以有點麻煩。
因爲最後要從開始,所以最後取模完要加一個,那麼,在取模之前就要減一個,然後就是這樣
如果要從號點開始,往前個點,就是
好了,複雜度,有點勉強
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
int n,m,p;
int a[1001];
int t[1001][1001];
int sum[1001][1001];
int f[1001];
int main(){
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&t[i][j]);
}
}
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int j=1;j<=m;j++){
for(int i=1;i<=n;i++){
sum[i][j]=sum[(i-1-1+n)%n+1][j-1]+t[(i-1-1+n)%n+1][j];
}
}
for(int i=1;i<=m;i++){
f[i]=-0x3fffffff;
for(int j=1;j<=n;j++){
for(int k=1;k<=p&&k<=i;k++){
int last=((j-k-1)%n+n)%n+1;
f[i]=max(f[i],f[i-k]+sum[j][i]-sum[last][i-k]-a[last]);
}
}
}
printf("%d",f[m]);
return 0;
}
然後,發現剛纔那個式子其實就是(爲了看得清楚,環先不考慮):
這一坨,發現好像可以用隊列維護。
用維護,然後複雜度就成了,終於沒了。
代碼
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
int n,m,p;
int a[1001];
int t[1001][1001];
int sum[1001][1001];
int f[1001];
int q[1001][1001],k[1001][1001],head[1001],tail[1001];
int main(){
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&t[i][j]);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
q[i][0]=-a[i];
}
for(int j=1;j<=m;j++)
for(int i=1;i<=n;i++)
sum[i][j]=sum[(i-1-1+n)%n+1][j-1]+t[(i-1-1+n)%n+1][j];
for(int i=1;i<=m;i++){
f[i]=-0x3fffffff;
for(int j=1;j<=n;j++){
int l=((j-i-1)%n+n)%n+1;
while(head[l]<=tail[l]&&k[l][head[l]]+p<i)head[l]++;
if(head[l]<=tail[l])f[i]=max(f[i],q[l][head[l]]+sum[j][i]);
}//這部分是找到最佳的一個k,然後下面是更新序列,注意千萬不能並在一起,因爲f[i]還沒有更新完
for(int j=1;j<=n;j++){
int l=((j-i-1)%n+n)%n+1;
int x=f[i]-sum[j][i]-a[j];
while(head[l]<=tail[l]&&q[l][tail[l]]<=x)tail[l]--;
k[l][++tail[l]]=i;
q[l][tail[l]]=x;
}
}
printf("%d",f[m]);
return 0;
}