1. 程式人生 > >codeforces 1077F2. Pictures with Kittens (hard version)單調佇列+dp

codeforces 1077F2. Pictures with Kittens (hard version)單調佇列+dp

div3挑戰一場藍,大號給基佬紫了,結果從D開始他開始瘋狂教我做人??表演如何AKdiv3????

比賽場上:A 2 分鐘,B題蜜汁亂計數,結果想得繞進去了20多分鐘,至此GG,C秒出,D。。。還在想怎麼做就告訴我二分答案,好那繼續秒出。他看F我看E,沒思路互換,F題都讀了半天,其實就是我YY的題意,然後發現還是沒N^3dp的想法,發現並不是區間dp,其實之前我E想到了列舉等差數列的項數,只是發現找不了起點(那不是找終點就好了)。基佬紫:列舉項數啊,我????然後他寫完我就發現自己又傻了,rush完,想了5分鐘F,發現瞭如何n^3dp,發現兩個人思路一致,然後他1A了,然後我讀秒交了兩發,wa7,然後他說應該是單調棧優化,,結果真是,,他就這麼AK了。。。然後我就睡覺了,第二天晚上,F1交了14發都是WA7,於是看別人的程式碼,一通胡改完就跑路了。於是今天中午頹廢星人開始搞F2,想了一會兒感覺就是維護X個單調佇列就好了,注意的是必須開個tmp陣列,否則可能用之前已經更新了的更新這個位置,也就是內層兩次for,同時未成功轉移到的狀態不應放入單調佇列。然後一開始的寫法感到不適,就找了找題解,寫起來快多了。PS:我dp真的菜。

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define fi first
#define pb push_back
#define se second
#define rep(i,a,b)for(int i=a;i<=b;i++)
using namespace std;

const int maxn=5005;
deque<pair<int,ll> >q[maxn];
ll a[maxn];
ll dp[maxn][maxn];
ll tmp[maxn];
ll n,k,x;
int main()
{
	memset(dp,-1,sizeof(dp));
	scanf("%lld%lld%lld",&n,&k,&x);
	rep(i,1,n)scanf("%lld",&a[i]);
	q[0].pb(mp(0,0));
	for(int i=1;i<=n;i++)
	{
		memset(tmp,0,sizeof(tmp));
		for(int j=1;j<=x;j++)
		{
			while(!q[j-1].empty()&&q[j-1].front().fi<i-k)q[j-1].pop_front();
			if(!q[j-1].empty())tmp[j]=q[j-1].front().se+a[i];
		}
		for(int j=1;j<=x;j++)
		{
			while(!q[j].empty()&&q[j].back().se<tmp[j])q[j].pop_back();
			if(tmp[j])q[j].push_back(mp(i,tmp[j]));
		}
	}
	ll ans=-1;
	while(!q[x].empty()&&q[x].front().fi<=n-k)q[x].pop_front();
	if(!q[x].empty())ans=q[x].front().se;
	if(ans>0)cout<<ans<<"\n";
	else cout<<-1<<"\n";
}