• CF771E Bear and Rectangle Strips


    一、题目

    点此看题

    二、解法

    首先设计出暴力 (dp),设 (dp[i][j]) 表示第一行考虑到 (i),第二行考虑到 (j) 的最大得分,先写转移:

    • 扩展第一行,可以无得分让 (i+1);可以选从 (i+1) 开始的和为 (0) 的段(选右端点最小的)
    • 扩展第二行,可以无得分让 (j+1),可以选从 (j+1) 开始的和为 (0) 的段。
    • (i=j) 时,同时扩展两行,选一个 (i+1) 开始的何为 (0) 的矩阵。

    优化的关键是只有 (i=j) 时两行的转移才有交叉,否则两行的转移是相对独立的。一个至关重要的 ( t observation) 是当 (i ot=j) 时,我们只用扩展较小的那一行(指 (i,j) 比较出来较小)。因为如果不考虑第三种转移那么先扩展哪一行都是没关系的,否则扩展较小的一行就更有利于考虑第三种转移。

    那么我们以 (dp[i][i]) 为转移主体,也就是考虑两行前 (i) 列的最大得分,对于 (i ot=j) 的扩展,我们只需要找到最小的 (j) 使得 (dp[i][j]=dp[i][i]+1)(或者 (dp[j][i]=dp[i][i]+1)),因为如果 (dp[i][j]>dp[i][i]+1) 那么说明某一行扩展多了,不符合上述结论所以自然不用考虑。

    转移的时候维护那个 (j) 即可,时间复杂度 (O(n))

    三、总结

    考虑有效转移是优化的重要方法,也就是如果某一种转移的作用会在以后被解决那么我们就不用考虑它。

    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <map>
    using namespace std;
    const int M = 300005;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,a[2][M],nx[3][M],s[3],dp[M];map<int,int> mp[3];
    struct node
    {
    	int x,y,c;
    };vector<node> vc[M];
    void add(int x,int y,int c)
    {
    	dp[max(x,y)]=max(dp[max(x,y)],c);
    	vc[min(x,y)].push_back(node{x,y,c});
    }
    void extend(int x,int y,int c)
    {
    	if(x<n)
    	{
    		add(x+1,y,c);
    		int i=nx[0][x+1];
    		if(i) add(i,y,c+1);
    	}
    	if(y<n)
    	{
    		add(x,y+1,c);
    		int i=nx[1][y+1];
    		if(i) add(x,i,c+1);
    	}
    	if(x<n && x==y)
    	{
    		int i=nx[2][x+1];
    		if(i) add(i,i,c+1);
    	}
    }
    signed main()
    {
    	n=read();
    	for(int i=0;i<2;i++)
    		for(int j=1;j<=n;j++)
    			a[i][j]=read();
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=0;j<3;j++)
    			mp[j][s[j]]=i;
    		s[0]+=a[0][i];
    		s[1]+=a[1][i];
    		s[2]+=a[0][i]+a[1][i];
    		for(int j=0;j<3;j++)
    			if(mp[j][s[j]]) nx[j][mp[j][s[j]]]=i;
    	}
    	for(int i=0;i<n;i++)
    	{
    		extend(i,i,dp[i]);
    		int l=n+1,r=n+1;
    		for(node a:vc[i])
    		{
    			if(a.y==i && a.c==dp[i]+1)
    				l=min(l,a.x);
    			if(a.x==i && a.c==dp[i]+1)
    				r=min(r,a.y);
    		}
    		if(l<=n) extend(l,i,dp[i]+1);
    		if(r<=n) extend(i,r,dp[i]+1);
    	}
    	printf("%lld
    ",dp[n]);
    }
    
  • 相关阅读:
    c++中的stack实现
    非虚函数是静态绑定
    函数返回const,以便控制访问
    析构函数为虚函数
    c++中初始化列表顺序和声明顺序一致
    define的误用
    模板就是让编译器帮你写代码
    mysql代码中设置变量
    拼接index
    python import vs from import
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14999074.html
Copyright © 2020-2023  润新知