【動態規劃】聰明伶俐的香穗子
阿新 • • 發佈:2018-12-23
Problem 4 聰明伶俐的香穗子
香穗子遇到難題了.
題目是這樣的,一個序列上有n個整數,現在你要取m個,且這m個數的任意兩個不能相隔的太近,否則這樣會太醜,現在問你最大能得到多大的和
輸入:
第一行三個數n,m,k,分別表示n個數,取m個,且m箇中的任意兩個位置差要大於等於K
接下來一行,有n個整數,表示序列上的每個數
輸出:
最大和
Sample Input
4 2 2
3 4 -5 1
Sample Output
5
資料範圍:
n<=10000,m<=100,m<=n
答案保正小於 Maxlongint
看起來很像是單調佇列,但是完全用不著,單調佇列怎麼說也要難除錯一些。
列舉最後一選,考慮到最後一選與上次一選有關係,但是隻是上一選的位置有關係,沒有其他更多關係,因此,我們不需要最後一選的狀態記錄。
f[i][j] = max(f[k][j-1] + a[i]),i-k>=K。因此就限定了k的取值區間,但是因為已經說過與最後一選沒有關係,因此我們可以轉換一下狀態表示,表示“前”i個數選j個。
因此f[i][j]=max(f[i-1][j] , f[i-K][j-1]+a[i])。
用單調佇列也不是沒法做。
f[i][j] = max(f[k][j-1] + a[i]),i-k>=K。
觀察發現,只與上一行的j左邊的區域有關,因此我們可以讓動規和單調佇列的維護剛好非同步一行的位置,即用上一行的j左邊的f值來維護單調佇列。
但是要注意每一行對應一個單調佇列,所以列舉i的時候一定要將單調佇列清空,一開始就因為這個除錯了很久。
#include <cstdio> #include <string> #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) long a[10010]; long f[10010][101]; long getint() { long rs=0;bool sgn=1;char tmp; do tmp = getchar(); while (!isdigit(tmp)&&tmp-'-'); if (tmp == '-'){tmp=getchar();sgn=0;} do rs=(rs<<3)+(rs<<1)+tmp-'0'; while (isdigit(tmp=getchar())); return sgn?rs:-rs; } int main() { freopen("4.in","r",stdin); freopen("4.out","w",stdout); long n = getint(); long m = getint(); long k = getint(); for (long i=1;i<n+1;i++) a[i] = getint(); memset(f,~0x3f,sizeof f); for (long i=1;i<n+1;i++) { f[i][1] = max(f[i-1][1],a[i]); } for (long i=k;i<n+1;i++) { for (long j=2;j<m+1;j++) { f[i][j] = max(f[i][j],f[i-1][j]); if (i >= k) f[i][j] = max(f[i][j],f[i-k][j-1]+a[i]); } } printf("%ld",f[n][m]); return 0; }
#include <cstdio>
#include <string>
#include <cstring>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
long getint()
{
long rs=0;bool sgn=1;char tmp;
do tmp = getchar();
while (!isdigit(tmp)&&tmp-'-');
if (tmp == '-'){tmp=getchar();sgn=0;}
do rs=(rs<<3)+(rs<<1)+tmp-'0';
while (isdigit(tmp=getchar()));
return sgn?rs:-rs;
}
long a[10010];
long que[10010];
long f[10010][2];
int main()
{
freopen("4.in","r",stdin);
freopen("4.out","w",stdout);
long n = getint();
long m = getint();
long k = getint();
if (m == 0)
{
printf("0");
return 0;
}
long l = 0;
long r = 0;
long ths = 0;
long pre = 1;
for (long i=1;i<n+1;i++)
{
a[i] = getint();
f[i][ths] = a[i];
}
f[0][ths] = -0x3f3f3f3f;
for (long j=2;j<m+1;j++)
{
ths ^= 1; pre ^= 1;
for (long i=0;i<n+1;i++)
f[i][ths] = -0x3f3f3f3f;
for (long i=k+1;i<n+1;i++)
{
if (f[i-k][pre] > -0x3f3f3f3f)
{
while (l<r&&que[r]<=f[i-k][pre]) r--;
que[++r] = f[i-k][pre];
f[i][ths] = que[l+1] + a[i];
}
}
l = 0;
r = 0;
}
long ans = 0;
for (long i=0;i<n+1;i++)
{
ans = max(ans,f[i][ths]);
}
printf("%ld",ans);
return 0;
}