【Codeforces436D】Pudding Monsters
阿新 • • 發佈:2019-02-05
題意:
- 開始有無限長的一段格子,有
n 個格子種有布丁怪獸,一開始連續的布丁怪獸算一個布丁怪獸。 - 每回合你可以將一個布丁怪獸向左或右移動,他會在碰到第一個布丁怪獸時停下,並與其合併。
- 如果最左邊的怪獸向左,你可以認為是將其移動到了無窮遠處。
- 有
m 個特殊格子,詢問最終你最多可以讓幾個特殊的格子上被布丁覆蓋。 n≤10000,m≤2000 。
題解:
- 首先考慮兩種狀態:
f[i] 表示前i 個布丁(相同的布丁怪獸算長度個)最多覆蓋的特殊格子數,g[i] 表示前i 個布丁,第i 個不動的情況下最多覆蓋的特殊格子數,sum(l,r) 表示[l,r] 區間中有多少個特殊格子。那麼答案就是f[n] 。 - 考慮如何轉移:
- 第一種:
- 設當前轉移座標為
r=a[i] (當前列舉到第i 個布丁)。 - 列舉在
r 左邊的特殊格子位置l=b[j](b[j]<=a[i]) ,想要覆蓋[l,r] 區間的所有特殊格子,就至少需要另外r−l 個布丁,即i≥r−l+1 ,那麼可以得到轉移方程1: g[i]=max(g[i],f[i−(r−l)−1]+sum(l,r)) - 第二種:
- 設當前轉移座標為
l=a[i] (當前列舉到第i 個布丁)。 - 列舉在
l 右邊的特殊格子位置r=b[j](b[j]<=a[i]) ,想要覆蓋[l,+1r] 區間的所有特殊格子,就至少需要另外r−l 個布丁,即i+r−l≤n ,那麼可以得到轉移方程2: f[i+r−l]=max(f[i+r− - 第三種:
- 顯然可以發現轉移方程3:
f[i]=max(f[i],f[i−1]+[sum(a[i],a[i])==1]) g[i]=max(g[i],g[i−1]+[sum(a[i],a[i])==1]) - 然後我們發現這兩個陣列其實可以合併,一起轉移,於是就成功縮短了程式碼。
- 注意到我們沒有考慮一個怪獸不只是佔了一格的情況,我們可以在原來轉移的基礎上引入
L[i],R[i] 表示第i個布丁所屬的怪獸的最左邊格子編號和最右邊格子編號,這樣就能解決上述情況。
程式碼:
#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 200009
#define M 2009
using namespace std;
int n,m,a[N],b[M],sum[N],dp[N],L[N],R[N];
int read()
{
int x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
int s=ch-'0';
while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
return s*x;
}
int main()
{
n=read(),m=read();
for (int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+n+1);
a[0]=a[1]-1000,a[n+1]=a[n]+1000;
for (int i=1;i<=n;++i)
if (a[i]==a[i-1]+1) L[i]=L[i-1];
else L[i]=i;
for (int i=n;i;--i)
if (a[i]==a[i+1]-1) R[i]=R[i+1];
else R[i]=i;
sum[0]=0;
for (int i=1;i<=m;i++) b[i]=read(),sum[b[i]]++;
sort(b+1,b+m+1);
for (int i=1;i<=200000;i++) sum[i]+=sum[i-1];
for (int i=1;i<=n;i++)
{
dp[i]=max(dp[i],dp[i-1]);
int Max;
if (L[i]==i) Max=dp[i-1]+sum[a[i]]-sum[a[i]-1];
else Max=-10000000;
dp[i]=max(dp[i],Max);
for (int l=1;b[l]<=a[i]&&l<=m;l++)
if (i-(a[i]-b[l])>=1)
{
dp[i]=max(dp[i],dp[L[i-(a[i]-b[l])]-1]+sum[a[i]]-sum[b[l]-1]);
Max=max(Max,dp[L[i-(a[i]-b[l])]-1]+sum[a[i]]-sum[b[l]-1]);
}
for (int r=m;b[r]>=a[i]&&r;r--)
if (i+b[r]-a[i]<=n)
dp[R[i+b[r]-a[i]]]=max(dp[R[i+b[r]-a[i]]],Max+sum[b[r]]-sum[a[i]]);
}
printf("%d\n",dp[n]);
return 0;
}