zoukankan      html  css  js  c++  java
  • 【JZOJ2320】诡异游戏【dp】【堆】

    题目大意:

    题目链接:https://jzoj.net/junior/#main/show/2320
    在这里插入图片描述


    思路:

    被C组的题目血虐qwqqwq
    在这里插入图片描述
    感觉这道题还是不止C组难度的啊。拿到B组去应该也没几个人可以做出来。害得我一下午没有改A组题


    把每一个花看成一个点。
    首先由一个很显然的性质。如果我们已经取好了[1,x][1,x]的所有花,那么我们下次一定会取一个连续区间[x+1,y][x+1,y]的所有花。也就是说,不会存在某一个时刻我们取的花是不连续的。任意时刻取的花一定是一个左端点为1的连续区间。
    所以有一个相对明显的dpdp:设f[i]f[i]表示取完[1,i][1,i]所有的花并且走到点ii所需要的最小时间。
    那么就可以枚举这一次取的花的区间[j,i][j,i],那么我们需要求的就是从第jj朵花开始,在第ii朵花结束,并且取完[j,i][j,i]所有花的最少花费时间。
    那么如果我们第二次经过一朵花时,这朵花已经种下了,那么就不需要花费任何的时间等待。所以这样子所花费的时间如下图
    在这里插入图片描述
    其中红色线条表示采摘其中任意一朵花花费的时间。
    我们发现,从第一次经过这个点,准备放下花,到我我们最后一次经过这个点,采摘这朵花,所需要的时间(红色线条)正好为2(a[i]a[j])2(a[i]-a[j])
    所以无论我们采摘奶一个花,我们花费的时间是与这朵花的位置无关的。
    但是如果一朵花所需的等待时间mm是大于2(a[i]a[j])2(a[i]-a[j])的话,那么我们就得等待m2(a[i]a[j])m-2(a[i]-a[j])秒。也就是说,采摘[l,r][l,r]的花,我们需要花费时间为max(a[r]a[l],m)max(a[r]-a[l],m)
    所以这样我们就可以轻松的设计出一个O(n2)O(n^2)dpdp
    f[i]=min(f[i],f[j1]+a[i]a[j1]+max(2×(a[i]a[j]),m))f[i]=min(f[i],f[j-1]+a[i]-a[j-1]+max(2 imes (a[i]-a[j]),m))
    其中a[i]a[j1]a[i]-a[j-1]是从上一个结束的花(j1)(j-1)ii的时间。
    那么这样就可以获得50pts50pts的高分。
    考虑如何优化这个dpdp。我们发现这个dpdp最关键的地方就是maxmax,如果我们知道谁大谁小就可以把这个maxmax省掉了。
    也就是说
    2×(a[i]a[j])>m2 imes (a[i]-a[j])>m时,原方程为
    f[i]=min(f[i],f[j1]+a[i]a[j1]+2×(a[i]a[j]))f[i]=min(f[i],f[j-1]+a[i]-a[j-1]+2 imes (a[i]-a[j]))
    化简
    f[i]=min(f[i],f[j1]a[j1]2a[j]+3a[i])f[i]=min(f[i],f[j-1]-a[j-1]-2a[j]+3a[i])
    同理,当m>2×(a[i]a[j])m>2 imes (a[i]-a[j]),原方程为
    f[i]=min(f[i],f[j1]+a[i]a[j1]+m)f[i]=min(f[i],f[j-1]+a[i]-a[j-1]+m)
    我们发现,在枚举ii时,3a[i]3a[i]a[i]a[i]都是固定的,所以我们就只需要分别维护f[j1]a[j1]2a[j]f[j-1]-a[j-1]-2a[j]f[j1]+a[i]a[j1]f[j-1]+a[i]-a[j-1]的最小值即可。
    同时,容易发现在ii递增的过程中,满足2(a[i]a[j])>m2(a[i]-a[j])>m的花jj一定是一个区间[1,x][1,x]xx是单调不降的。所以我们就只要在把ii每往后挪一位时,利用单调不降的性质,维护好对应的有哪一些花是满足2(a[i]a[j])>m2(a[i]-a[j])>m,又有哪一些花是满足2(a[i]a[j])<m2(a[i]-a[j])<m的,然后分别用两个堆维护一下它们的最小值,然后取minmin即可。
    注意堆需要支持删除任意数字,那么就只能手写可删除堆了。
    同时花的下标达到了10910^9级别,所以需要开两个mapmap,别分记录字典序和一个数出现的个数。这样复杂度又增加了loglog
    细节还是很多了,调了我一个下午+晚上。
    时间复杂度O(nlog2n)O(nlog^2 n)。比较卡,最好吸氧(狗头保命


    代码:

    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #include <map>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const ll N=100010,Inf=1e18;
    ll n,t,m,j,a[N],f[N];
    
    struct Heap
    {
        ll a[N],tot;
        map<ll,ll> way,cnt;
        //ll cnt[N];
        
        ll size()
        {
            return tot;
        }
        
        ll top()
        {
        	if (!tot) return Inf;
            return a[1];  
        }
        
        void push(ll x) 
        {
            cnt[x]++;
            if (cnt[x]>1) return;
            a[++tot]=x;
            ll fa=(tot>>1),k=tot;
            way[x]=way[a[fa]]*2+(tot&1);
            while (a[fa]>a[k]&&fa)
            {
                swap(way[a[k]],way[a[fa]]);
                swap(a[k],a[fa]);
                k=fa; fa>>=1; 
            }
        }
        
        void pop(ll x)
        {
            cnt[a[x]]--;
            if (cnt[a[x]]) return;
            swap(way[a[x]],way[a[tot]]);
            swap(a[x],a[tot]); 
            way[a[tot]]=0;
            a[tot]=0;
            tot--;      
            ll son=(x<<1);
            while ((a[son]<a[x]&&son<=tot)||(a[son+1]<a[x]&&son+1<=tot))      
            {
                if (a[son+1]<a[son]&&son+1<=tot) son++;
                swap(way[a[x]],way[a[son]]);
                swap(a[x],a[son]);
                x=son; son<<=1; 
            }
        }
    }q1,q2; 
    
    int main()
    {
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    	scanf("%lld%lld%lld",&n,&t,&m); n++;
    	for (ll i=2;i<=n;i++)
    		scanf("%lld",&a[i]);
    	f[1]=0; j=2;
    	for (ll i=2;i<=n;i++)
    	{
    		q2.push(f[i-1]-a[i-1]+m);
    		for (j<=i;2LL*(a[i]-a[j])>m;j++)
    		{
    			q2.pop(q2.way[f[j-1]-a[j-1]+m]);
    			q1.push(f[j-1]-a[j-1]-2*a[j]);
    		}
    		f[i]=min(q1.top()+3*a[i],q2.top()+a[i]);
    		//if (i==30) printf("%lld
    ",f[i]);
    	}
    	printf("%lld",f[n]+t-a[n]);
    	return 0;
    }
    
  • 相关阅读:
    ACM的算法分类 2015-04-16 14:25 22人阅读 评论(0) 收藏
    初学Larevel 2014-08-21 11:24 90人阅读 评论(0) 收藏
    初学PHP&MySQL 2014-05-31 12:40 92人阅读 评论(0) 收藏
    codeforces 570 E. Pig and Palindromes (dp)
    codeforces 570 D. Tree Requests (dfs序)
    poj 2157 Maze (bfs)
    cf 570 C. Replacement (暴力)
    cf 570B B. Simple Game(构造)
    cf 570 A. Elections
    hdu 1429胜利大逃亡(续) (bfs+状态压缩)
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998031.html
Copyright © 2011-2022 走看看