当前位置: 首页 > 工具软件 > rr-project > 使用案例 >

2020 ICPC亚洲区域赛(沈阳)H-The Boomsday Project(双指针+dp)

柳飞飙
2023-12-01

H-The Boomsday Project

Code1

暴力我为人人区间转移
O { N ∑ q log ⁡ N } O\{N\sum q\log N \} O{NqlogN}

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{
    T res=0;T fg=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}
    while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res*fg;
}
ll f[300010*4],tag[300010*4];
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,m;ll RR;
int tot;

void update(int u,int l,int r,int L,int R,ll v)
{
    if(L>R) return;
    if(L<=l&&r<=R) 
    {
        tag[u]=min(tag[u],v);
        f[u]=min(f[u],v);
        return;
    }
    int mid=l+r>>1;
    if(L<=mid)
        update(u<<1,l,mid,L,R,v);
    if(R>mid)
        update(u<<1|1,mid+1,r,L,R,v);
}
ll query(int u,int l,int r,int pos,ll v)
{
    if(l==r) return min(f[u],v);
    
    v=min(v,tag[u]);
    int mid=l+r>>1;
    if(pos<=mid) return query(u<<1,l,mid,pos,v);
    else return query(u<<1|1,mid+1,r,pos,v);
}
struct nodea
{
    int d,k,c;
}a[510];
int g[300010],h[300010];
struct nodeb
{
    int p,q;
    bool operator<(const nodeb &o)const
    {
        return p<o.p;
    }
}b[300010];
int mp[300010];
int main()
{
    

    n=rd(),m=rd();RR=rd<ll>();
    for(int i=1;i<=n;i++) a[i].d=rd(),a[i].k=rd(),a[i].c=rd();
    
    for(int i=1;i<=m;i++) 
    {
        b[i].p=rd();b[i].q=rd();
        mp[i]=b[i].p;
    }
    sort(mp+1,mp+1+m);
    sort(b+1,b+1+m);
    for(int i=1;i<=m;i++)
    {
        b[i].p=lower_bound(mp+1,mp+1+m,b[i].p)-mp;
        
        for(int j=tot+1;j<=tot+b[i].q;j++) g[j]=b[i].p;
        
        h[b[i].p]=tot+b[i].q;
        tot+=b[i].q;
    }
    
    mp[++m]=2e9;  
    
    memset(f,0x3f,sizeof f);
    memset(tag,0x3f,sizeof tag);
    update(1,0,tot,0,0,0);
    
    for(int i=0;i<tot;i++)
    {
        ll v=query(1,0,tot,i,INF);
        
        update(1,0,tot,i+1,i+1,v+RR);
        for(int j=1;j<=n;j++) 
        {
            int l=i+1,r;
            r=i+a[j].k;
            int d=lower_bound(mp+1,mp+1+m,g[i+1]+a[j].d-1)-mp;
            if(mp[d]>g[i+1]+a[j].d-1) --d;
            r=min(r,h[d]);
            update(1,0,tot,l,r,v+a[j].c);
        }
    }
    printf("%lld\n",query(1,0,tot,tot,INF));
    return 0;
}

不需要区间覆盖转移,不难发现只需转移右端点即可。由于具有单调性可以双指针预处理。

Code2

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{
    T res=0;T fg=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}
    while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res*fg;
}

int n,m;ll R;
int tot;
struct nodea
{
    int d,k,c;
}a[510];
int g[300010];
ll f[300010];
struct nodeb
{
    int p,q;
    bool operator<(const nodeb &o)const
    {
        return p<o.p;
    }
}b[300010];
int to[510][300010];
int main()
{

    n=rd(),m=rd();R=rd<ll>();
    for(int i=1;i<=n;i++) a[i].d=rd(),a[i].k=rd(),a[i].c=rd();
    
    for(int i=1;i<=m;i++) b[i].p=rd(),b[i].q=rd();

    sort(b+1,b+1+m);
    for(int i=1;i<=m;i++)
    {
        for(int j=tot+1;j<=tot+b[i].q;j++) g[j]=b[i].p; //第j次骑车在第b[i].p天
        tot+=b[i].q;
    }
    
    for(int j=1;j<=n;j++)
        for(int i=0,k=1;i<tot;i++)
        {
            while(k<=tot&&g[k]-g[i+1]+1<=a[j].d) k++;
            to[j][i]=k-1;
        }
    memset(f,0x3f,sizeof f);
    
    f[0]=0;
    for(int i=0;i<tot;i++)
    {
        f[i+1]=min(f[i+1],f[i]+R);
        for(int j=1;j<=n;j++) 
        {
            int r=min(i+a[j].k,to[j][i]);
            f[r]=min(f[r],f[i]+a[j].c);
        }
    }
    printf("%lld\n",f[tot]);
    return 0;
}
 类似资料: