zoukankan      html  css  js  c++  java
  • 【BZOJ1563】【NOI2009】—诗人小G(决策二分栈优化dp)

    传送门

    O(n2)dpO(n^2)dp应该都会吧……

    f[i]=min(f[j]+(sum[i]sum[j]L)pf[i]=min(f[j]+(sum[i]-sum[j]-L)^p

    我们发现这个pp次方是单调的
    考虑2个决策点对后面的贡献
    一定存在一个分界点
    满足前面从第一个决策转移更优,后面从第二个转移更优

    我们就可以用一个队列维护这样一个单调的分界点
    每次转移就可以了

    注意会爆long longlong long
    long doublelong double

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    #define ll long long
    inline char gc(){
        static char ibuf[RLEN],*ob,*ib;
        (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ob==ib)?EOF:*ib++;
    }
    #define gc getchar
    #define ld  double 
    inline int read(){
        char ch=gc();
        int res=0,f=1;
        while(!isdigit(ch))f^=(ch=='-'),ch=gc();
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
        return f?res:-res;
    }
    const int N=100005;
    const double eps=1e-6;
    char s[N][35];
    int pr[N],stk[N],hd,tl,k[N],sum[N];
    ld f[N];
    int n,L,p;
    inline ld ksm(ld a,ld res=1){
    	for(int b=p;b;b>>=1,a=a*a)(b&1)?res=res*a:0;
    	return res;
    }
    inline ld calc(int i,int j){
    	return f[j]+ksm(abs(L-sum[i]+sum[j]));
    }
    inline int bound(int i,int j){
    	int l=i,r=n+1;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(calc(mid,i)>=calc(mid,j))r=mid-1;
    		else l=mid+1;
    	}
    	return l;
    }
    int main(){
    	int T=read();
    	while(T--){
    		n=read(),L=read()+1,p=read();
    		for(int i=1;i<=n;i++)scanf("%s",s[i]),sum[i]=sum[i-1]+strlen(s[i])+1;
    		hd=1,tl=1;stk[1]=0;
    		for(int i=1;i<=n;i++){
    			while(hd<tl&&k[hd]<=i)hd++;
    			f[i]=calc(i,stk[hd]),pr[i]=stk[hd];
    			while(hd<tl&&k[tl-1]>=bound(stk[tl],i))tl--;
    			k[tl]=bound(stk[tl],i),stk[++tl]=i;
    		}
    		if(f[n]>1e18)cout<<"Too hard to arrange"<<'
    ';
    		else{
    			printf("%.0lf
    ",f[n]);
    			stk[0]=n,hd=1,tl=0;
    			for(int i=n;i;stk[++tl]=i=pr[i]);
    			for(int i=tl;i;i--){
    				for(int j=stk[i]+1;j<stk[i-1];j++){
    					cout<<s[j]<<" ";
    				}
    				cout<<s[stk[i-1]]<<'
    ';
    			}
    		}
    		puts("--------------------");
    	}
    }
    
  • 相关阅读:
    3.这个月有几天?
    3.这个月有几天?
    3.这个月有几天?
    2.求一个整数有几位(简单字符串操作)
    Algs4-1.2.1编写一个Point2D的用例-分治法
    Algs4-1.2.1编写一个Point2D的用例
    Algs4-1.1.39随机匹配
    Algs4-1.1.38二分查找与暴力查找
    Algs4-1.1.37糟糕的打乱
    Algs4-1.1.36乱序检查
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145572.html
Copyright © 2011-2022 走看看