• P6820 [PA2012]Two Cakes DP状态优化


    题意:

    戳这里

    分析:

    很久以前做过的题,在巨佬 fgf 的帮助下又学了一遍

    • 暴力

    直接设 DP 状态 (f[i][j]) 表示第一个序列枚举到第 (i) 位,第二个序列枚举到第 (j) 位时的最短时间,按题意模拟就好了

    • 正解

    我们发现暴力做法中大部分的情况下 DP 都没有做出任何决策直接转移了,所以有好多状态是无用的。所以我们只考虑 (a[x]==b[y]) 这种特殊状态下的 DP,对于其他的情况直接转移向 (a[x]==b[y]) 的情况

    1. (a[x]==b[y])
    f[x]=min(dfs(x-1,y),dfs(x,y-1))+1;
    

    因为一个 (x) 一定只会对应一个 (y) ,所以这种情况只会遇到一次,那么直接对于 (x) 记忆化就可以了,之后遇到直接返回值就可以了

    1. (a[x]!=b[y])

    我们需要找到之前他们刚好相等时的另一个点,我们注意到当转移是不会影响两个点的差值,所以我们直接对于每一类差值,存一下它们下一次相同时的点的位置,然后直接二分的查找

    复杂度 (O(n log n)) , 因为决策点只有 (n) 个,每一次不同的情况都会 (O(log n)) 的跳

    代码:

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    #define lc rt<<1
    #define rc rt<<1|1
    #define pb push_back
    #define fir first
    #define sec second
    
    using namespace std;
    
    namespace zzc
    {
    	inline int read()
    	{
    		int x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 1e6+5;
    	int a[maxn],b[maxn],pos[maxn],f[maxn];
    	int n;
    	vector<int> del[maxn<<1];
    	
    	int get(int id,int pos)
    	{
    		int l=0,r=del[id].size()-1,mid,res=0;
    		while(l<=r)
    		{
    			mid=(l+r)>>1;
    			if(del[id][mid]<=pos)
    			{
    				res=del[id][mid];
    				l=mid+1;
    			}
    			else r=mid-1;
    		}
    		return res;
    	}
    	
    	int dfs(int x,int y)
    	{
    		if(!x||!y) return x|y;
    		if(a[x]==b[y])
    		{
    			if(!f[x]) f[x]=min(dfs(x-1,y),dfs(x,y-1))+1;
    			return f[x]; 
    		}
    		int pre=get(x-y+n,x);
    		return pre?dfs(pre,y+pre-x)+(x-pre):max(x,y);
    	}
    	
    	void work()
    	{
    		n=read();
    		for(int i=1;i<=n;i++) a[i]=read();
    		for(int i=1;i<=n;i++)
    		{
    			b[i]=read();
    			pos[b[i]]=i;
    		}
    		for(int i=1;i<=n;i++) del[i-pos[a[i]]+n].pb(i);
    		printf("%d
    ",dfs(n,n));
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    NPOI创建Excel﹑合并单元格﹑设置单元格样式﹑边框
    MQTT 折腾笔记协议简读
    深度剖析Byteart Retail案例:仓储(Repository)及其上下文(Repository Context)
    MySQL简介,安装,简单使用
    技术改进方案模板
    【零基础学习iOS开发】【01开篇】
    DDD:主键映射,你一直在使用的企业应用模式
    自己写框架 实践 (Event Framework)
    无刷新页面
    Parallel Desktop,Mac OS X虚拟Win7
  • 原文地址:https://www.cnblogs.com/youth518/p/14063658.html
Copyright © 2020-2023  润新知