0x58 数据结构优化DP

补写一下

poj3171 设f[i]表示覆盖L~i的最小花费,把区间按左端点排序,枚举区间,f[a[i].r]=min{f[a[i].l~(a[top].r-1)]}+a[i].c (当然还要和原值比较的)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

struct node{int l,r,d;}a[31000];
bool cmp(node n1,node n2){return n1.r<n2.r;}

struct trnode
{
    int l,r,lc,rc,c;
}tr[210000];int trlen;
void bt(int l,int r)
{
    int now=++trlen;
    tr[now].l=l;tr[now].r=r;tr[now].c=(1<<30);
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
void change(int now,int p,int k)
{
    if(tr[now].l==tr[now].r){tr[now].c=k;return ;}
    
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(p<=mid)change(lc,p,k);
    else      change(rc,p,k);
    
    tr[now].c=min(tr[lc].c,tr[rc].c);
}
int getmin(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r)return tr[now].c;
    
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    
         if(r<=mid)  return getmin(lc,l,r);
    else if(mid+1<=l)return getmin(rc,l,r);
    else return min(getmin(lc,l,mid),getmin(rc,mid+1,r));
}

int f[110000];
int main()
{
    int n,L,R;
    scanf("%d%d%d",&n,&L,&R);L++,R++;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].d);
        a[i].l++,a[i].r++;
        if(a[i].r<L||R<a[i].l)i--,n--;
        if(a[i].l<L)a[i].l=L;
        if(R<a[i].r)a[i].r=R;
    }
    sort(a+1,a+n+1,cmp);
    
    int top=1; trlen=0,bt(L,R);
    memset(f,63,sizeof(f));
    for(int i=L;i<=R;i++)
    {
        while(top<=n&&a[top].r==i)
        {
            if(a[top].l==L)
            {
                if(a[top].d<f[i])
                    f[i]=a[top].d, change(1,i,f[i]);
            }
            else 
            {
                int k=getmin(1,a[top].l-1,a[top].r-1)+a[top].d;
                if(k<f[i])
                    f[i]=k, change(1,i,f[i]);
            }
            top++;
        }
    }
    if(f[R]==f[0])printf("-1\n");
    else printf("%d\n",f[R]);
    return 0;
}
poj3171

hdu5542 f[i][j]表示枚举到第几个位置,长度为j的严格上升序列有多少(注意一定包括第i个位置)

f[i][j]=∑(k<j&&a[k]<a[j])f[k][j-1] 这里先离散化,然后开m个树状数组记录,想想cdq分治,时间维有序第一个限制不管,第二个用树状数组解决。实际操作中,是不用定义数组的,直接插入树状数组中相应位置即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int mod=1e9+7;

int lslen;int s[1100][1100];
int lowbit(int x){return x&-x;}
void change(int x,int w,int k)
{
    while(x<=lslen)
    {
        s[w][x]=(s[w][x]+k)%mod;
        x+=lowbit(x);
    }
}
int getsum(int x,int w)
{
    int ret=0;
    while(x>0)
    {
        ret=(ret+s[w][x])%mod;
        x-=lowbit(x);
    }
    return ret;
}

//----------------bit---------------------

int a[1100],ls[1100];
int main()
{
    int T,T_T=0;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        lslen=0;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]), ls[++lslen]=a[i];
        sort(ls+1,ls+lslen+1);
        lslen=unique(ls+1,ls+lslen+1)-ls-1;
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(ls+1,ls+lslen+1,a[i])-ls;
            
        memset(s,0,sizeof(s));
        for(int i=1;i<=n;i++)
        {
            change(a[i],1,1);
            int li=min(i,m);
            for(int j=2;j<=li;j++)
                change(a[i],j,getsum(a[i]-1,j-1));
        }
        
        printf("Case #%d: %d\n",++T_T,getsum(lslen,m));
    }
    return 0;
}
hdu5542

 

posted @ 2018-08-13 15:48  AKCqhzdy  阅读(369)  评论(0编辑  收藏  举报