Luogu P3572 [POI2014] PTA-リトルバード問題ソリューション(単調キュー最適化DP)

トピックリンク

f [i] f [i]を設定しますf [ i ]は、鳥が1から1であることを意味します1本の木がiiにジャンプしますiツリーの最小コスト。

次に、ナイーブなO⁡(n 2)\ operatorname {O}(n ^ 2)On2変換方程式は次のとおりです。f[i] = f [j] + [d [j]≤d[i]] f [i] = f [j] + [d [j] \ le d [i]]f [ i ]=f [ j ]+[ d [ j ]d [ i ] ]、メリー中[d [j]≤d[i]] [d [j] \ le d [i]][ d [ j ]d [ i ] ]括弧内の条件が満たされている場合、それは11です。1、それ以外の場合は0 00

私たちは、のためにそれを見つけることができ、X <Y-X <Yバツ<Y

  • 如果f [x] <f [y] f [x] <f [y]f [ x ]<f [ y ]、次にxxxは間違いなく役に立たない。どこに転送されてもyyyはxxよりも優れているxは悪い、そしてxxxが最初に削除されます
  • 同様に、f [x] = = f [y] f [x] == f [y]の場合f [ x ]==f [ y ]d [x ] ≤d[y] d [x] \ le d [y]d [ x ]d [ y ]、次にxxxは役に立たないに違いない

次に、単調なキューのメンテナンスを使用できます。合計時間計算量はO⁡(n)\ operatorname {O}(n)です。On

#include<cstdio>
#include<iostream>
#include<deque>
#include<cstring>
using namespace std;
const int Maxn=1000000+10;
int a[Maxn],f[Maxn];
int n,m,k;
deque <int> q;
inline int read()
{
    
    
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return s*w;
}
void push(int pos)
{
    
    
	while(q.size())
	{
    
    
		int x=q.back();
		if(f[x]<f[pos] || f[x]==f[pos] && a[x]>a[pos])break;
		q.pop_back();
	}
	q.push_back(pos);
}
void pop(int i)
{
    
    
	while(q.size())
	{
    
    
		if(q.front()>=i-k)break;
		q.pop_front();
	}
}
int main()
{
    
    
//	freopen("in.txt","r",stdin);
	n=read();
	for(int i=1;i<=n;++i)
	a[i]=read();
	m=read();
	while(m--)
	{
    
    
		k=read();
		q.push_back(1);
		for(int i=2;i<=n;++i)
		{
    
    
			pop(i);
			int j=q.front();
			f[i]=f[j];
			if(a[j]<=a[i])++f[i];
			push(i);
		}
		printf("%d\n",f[n]);
		
		q.clear();
		memset(f,0,sizeof(f));
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/Brian_Pan_/article/details/107807988