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

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

我们很容易发现 $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;
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值