8.21练习——动态规划-决策单调性

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Love_mona/article/details/81910331

蒟蒻的垂死挣扎

昨天咕咕咕了。。。什么鬼爬岳麓山?反正是累得一批。

这两天都做的一道题,真是坑死了。各种坑,spj啊,longdouble啊,yyb啊。。。。

行。小总结,今晚放假,不过大概不会断吧。

 luogu P1912 [NOI2009]诗人小G

没想到yyb的第一道题就这么牛逼,贴总结了。

决策单调性
首先明确一点,如果i>j 则i的决策点一定大于等于j的决策点
那么我们考虑一个点怎么向后转移,我们可以二分找到当前点转移比以前所有点都更加优秀的一个后缀区间,为什么是后缀区间,因为如果x从i转移而来更优,则x以后的所有点从i转移一定更优。那么我们就能够确定这个i的影响范围了,经过一次次的不断更新,就能确认一个点的最优转移点。我们考虑用单调队列来维护这个更新,记录每个点的影响区间,每次先弹掉不合法区间以及一定不优的区间,然后我们二分到那个i点影响的后缀区间,修改上一位的区间右端点,并将当前区间加入队列。
>1e18问题
可以利用double类型的自带高精度来解决,但是会掉精度,所以开long double,最后转化为longlong输出即可。

题目不难,重在理解决策单调性的优化模式。

为什么说yyb坑,因为这货 define double long double. 我被这个卡了很久。

我待会儿再找他算账。 下面是代码。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<map>
#include<vector>
#define N 100100
#define ll long long
#define double long double
#define ls (now<<1)
#define rs ((now<<1)|1)
#define RG register
#define EPS 1e-7
#define inf 1e18
using namespace std;
inline int read(){
    RG int x=0,o=1; RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if(ch=='-') o=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1))+ch-'0',ch=getchar();
    return x*o;
}

int n,pre[N],Floor; ll L,P,len[N],sum[N]; double f[N];
struct mona { int j,l,r; } Q[N];
string ss[N];
inline double Pow(double x,int y){
	RG double ans=1;
	while(y) { if(y&1) ans*=x; x*=x,y>>=1; }
	return ans; 
}
inline void Ans(int now){
	if(!now) return ; Ans(pre[now]);
	for(RG int i=pre[now]+1;i<now;++i) cout<<ss[i]<<' ';
	cout<<ss[now]<<endl; return ;
}
inline double Get(int i,int j) { return f[j]+Pow(fabs(L-sum[i]+sum[j]-i+j+1),P); }

int main(){
	RG int T=read();
	while(T--){  RG int top=1,tail=0;
        memset(Q,0,sizeof(Q));
		n=read(),L=read(),P=read();
		for(RG int i=1;i<=n;++i) cin>>ss[i],len[i]=ss[i].length(),sum[i]=sum[i-1]+len[i];
		Q[++tail]=(mona) { 0,1,n };
		for(RG int i=1;i<=n;++i){
			while(tail>top&&Q[top].r<i) ++top;
			f[i]=Get(i,Q[top].j),pre[i]=Q[top].j,++Q[top].l;
			while(tail>top&&Get(Q[tail].l,i)<=Get(Q[tail].l,Q[tail].j)) --tail;
			int l=Q[tail].l,r=Q[tail].r,ans=Q[tail].r+1;
			while(l<=r){
				int mid=l+r>>1;
				if(Get(mid,i)<=Get(mid,Q[tail].j)) ans=mid,r=mid-1;
				else l=mid+1;
			}   Q[tail].r=ans-1; if(ans<=n) Q[++tail]=(mona) { i,ans,n };
		}
		if(f[n]>inf) puts("Too hard to arrange");
		else cout<<(ll) f[n]<<endl,Ans(n);
		puts("--------------------");
	}
}

这两天没白花,我大概会再刷几道练练手感吧,感觉这东西虽然模板固定,但是并不是那么死板,反而很灵活,这可能是DP最吸引我的一点吧。

加油。

猜你喜欢

转载自blog.csdn.net/Love_mona/article/details/81910331
今日推荐