首页 > 其他 > 详细

BZOJ 1563: [NOI2009]诗人小G (决策单调性,单调队列,二分)

时间:2020-04-03 00:17:07      阅读:77      评论:0      收藏:0      [点我收藏+]

这算是决策单调性入门题吧.  

我们很容易发现 $f[i]$ 的转移 $p_{i}$ 满足单调性,然后拿单调队列来维护就行.   

  • 对于队列中每个元素维护这个元素转移区间的右端点
  • 新加入一个点的时候和队尾比较一下,看队尾是否会被覆盖,弹掉无用元素.   

code: 

#include <bits/stdc++.h>       
#define ll long long       
#define N 100009  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;     
int n,L,P,s[N],q[N],k[N],pr[N];      
long double f[N];   
char str[N][33];    
long double qpow(long double x) 
{
    long double tmp=1;   
    for(int k=P;k;k>>=1,x*=x)   
        if(k&1) tmp*=x;   
    return tmp;    
}   
long double calc(int i,int j) { return f[j]+qpow(abs(s[i]-s[j]-L)); }
int find(int x,int y) 
{
    if(calc(n,x)<=calc(n,y))  
        return n+1;    
    int l=y,r=n+1,mid,ans=0; 
    while(l<=r) 
    {
        mid=(l+r)>>1;  
        if(calc(mid,x)>=calc(mid,y)) 
            ans=mid,r=mid-1; 
        else l=mid+1;   
    }       
    return ans;   
}
void solve() 
{   
    scanf("%d%d%d",&n,&L,&P),++L;    
    for(int i=1;i<=n;++i) 
    {
        if(scanf("%s",str[i]));                
        s[i]=s[i-1]+strlen(str[i])+1;   
    }        
    int h=1,t=1;   
    q[h]=0;   
    for(int i=1;i<=n;++i) 
    {
        while(h<t&&k[h]<=i) ++h;     
        f[i]=calc(i,q[h]),pr[i]=q[h];    
        while(h<t&&k[t-1]>=find(q[t],i)) --t;     
        k[t]=find(q[t],i),q[++t]=i,k[t]=n+1;  
    }   
    if(f[n]>1e18) printf("Too hard to arrange\n");   
    else 
    {
        printf("%.0Lf\n",f[n]);     
    }   
    puts("--------------------"); 
}                
int main() 
{ 
    // setIO("input");    
    int T;  
    scanf("%d",&T);   
    while(T--) solve();   
    return 0;
}

  

BZOJ 1563: [NOI2009]诗人小G (决策单调性,单调队列,二分)

原文:https://www.cnblogs.com/guangheli/p/12623724.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!