【DP】SRM552 PointErasing
2018-03-21 18:38
363 查看
题意:
在一个平面上,给出NN个点,现在重复进行如下操作:1、选择两个横,纵坐标均不同的点,并且要求以这两个点为顶点的矩形,必须满足矩形内部(不含边线)存在至少1个点,若不存在,则停止。
2、删去矩形内部的所有点。
现在求剩下的点的总数的所有可能结果
N≤50N≤50
分析:
首先,很容易发现,在某维坐标为最值的点是一定不会被包含的,因此,我们选中这些点,这些点组成的矩形如下:(注:这是样例7的图)
这样一来,结论就很清晰了:所有点都会被覆盖,但由于题目要求的是严格内部,所以红线画出的区域其实并没有被覆盖。也就是说,除了红线上的点,其它的点在任意一组方案中,最终都会被消掉。
那么我们再来找一下这条红线的严格定义:
其必然是由最左端的一个点向右,直到一个最高/最低点为止
以及由最右端的一个点向左,直到一个最高/最低点为止。
证明很简单,首先,很显然红线上的点必然和左端点/右端点在同一高度上,否则若其不是最高点,则必然会被以最高点与左端点/右端点形成的矩形覆盖。
在此基础上,若该点超过了从端点出发遇到的第一个最高/最低点,则其必然可以通过第一个最高/最低点与任意一个最低/最高点形成的矩形覆盖掉。
这样一来,我们需要考虑的范围就少了很多:左端点,右端点,最高/最低点均不能删,红线以外的点均会被删除。
现在考虑红线上的点:我们根据其是与左端点还是右端点高度相同,分成两个部分,分别处理(即左右两段红线)
这个时候,就可以通过DP来做了,定义DP[i][j]表示前i个点中,能否恰好删去j个点(1/0),具体转移和01背包基本相同。唯一不同的是,这里的物品不是隐式的:
为了表达方便,我们设A类点表示高于端点的点,B类点表示高度等于端点的点,C类点表示高度低于端点的点。
当我们访问到一个A类点时,我们查询其与所有之前的C类点之间的B类点的个数,这个个数即为“物品”的体积。仍然不明白可以看看代码。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> #define SF scanf #define PF printf #define MAXN 55 using namespace std; int maxh,minh,firh,lash,n; bool dp[MAXN][MAXN],res[MAXN]; int h[MAXN],cnt; int tag[MAXN]; vector<int> ans1,ans2,ans; void add1(int x,int y,int sum){ for(int i=sum;i<n;i++) dp[x][i]=dp[x][i]|dp[y][i-sum]; } void add2(int x,int y,int sum){ for(int i=sum;i<n;i++) dp[x][i]=dp[x][i]|dp[y][i-sum]; } class PointErasing{ public: vector<int> getOutcomes(vector<int> r1){ //SF("%d",&n); n=r1.size(); for(int i=0;i<n;i++){ SF("%d",&h[i]); h[i]=r1[i]; } firh=h[0],lash=h[n-1]; maxh=minh=firh; for(int i=0;i<n;i++){ maxh=max(maxh,h[i]); minh=min(minh,h[i]); } if(minh==maxh){ ans.push_back(n); return ans; } for(int i=0;i<n&&h[i]!=minh&&h[i]!=maxh;i++) if(h[i]==firh){ tag[i]=1; cnt++; } for(int i=n-1;i>=0&&h[i]!=minh&&h[i]!=maxh;i--) if(h[i]==lash){ tag[i]=2; cnt++; } for(int i=0;i<n;i++) if(tag[i]==0&&(h[i]==minh||h[i]==maxh)) cnt++; for(int i=0;i<n;i++) dp[i][0]=1; if(firh!=minh&&firh!=maxh){ int i=0; for(;i<n&&h[i]!=minh&&h[i]!=maxh;i++){ if(i!=0) for(int j=0;j<n;j++) dp[i][j]=dp[i-1][j]; int sum=0; if(h[i]>firh){ for(int j=i-1;j>=0;j--){ if(h[j]==firh) sum++; if(h[j]<firh) add1(i,j,sum); } } if(h[i]<firh){ for(int j=i-1;j>=0;j--){ if(h[j]==firh) sum++; if(h[j]>firh) add1(i,j,sum); } } } for(int j=0;j<n;j++) dp[i][j]=dp[i-1][j]; int sum=0; for(int j=i-1;j>=0;j--){ if(h[j]==firh) sum++; else add1(i,j,sum); } for(int j=0;j<n;j++) if(dp[i][j]==1) ans1.push_back(j); } else ans1.push_back(0); if(lash!=minh&&lash!=maxh){ int i=n-1; for(;i>=0&&h[i]!=minh&&h[i]!=maxh;i--){ if(i!=n-1) for(int j=0;j<n;j++) dp[i][j]=dp[i+1][j]; int sum=0; if(h[i]>lash){ for(int j=i+1;j<n;j++){ if(h[j]==lash) sum++; if(h[j]<lash) add2(i,j,sum); } } if(h[i]<lash){ for(int j=i+1;j<n;j++){ if(h[j]==lash) sum++; if(h[j]>lash) add2(i,j,sum); } } } int sum=0; for(int j=0;j<n;j++) dp[i][j]=dp[i+1][j]; for(int j=i+1;j<n;j++){ if(h[j]==lash) sum++; else add2(i,j,sum); } for(int j=0;j<n;j++) if(dp[i][j]==1) ans2.push_back(j); } else ans2.push_back(0); for(int i=0;i<ans1.size();i++) for(int j=0;j<ans2.size();j++) res[cnt-ans1[i]-ans2[j]]=1; for(int i=0;i<=n;i++) if(res[i]) ans.push_back(i); return ans; } };
相关文章推荐
- [DP] Topcoder SRM 552 DIV1 Hard. HolyNumbers
- srm 301 div2 1000 (经典dp, 括号匹配)
- SRM 626 D1L1: FixedDiceGameDiv1,贝叶斯公式,dp
- SRM 514 DIV1 500pt(DP)
- SRM 552 DIV2
- [树形DP] SRM 598 Div1 Hard TPS
- SRM 627 D2L3: BubbleSortWithReversals, dp, 冒泡排序
- SRM 596 D2 L2:ColorfulRoad,dp
- SRM 609 D2L3: VocaloidsAndSongs,dp
- SRM 602 D1L1:TypoCoderDiv1,dp
- TopCoder SRM 649 Div2 Problem 500 - CartInSupermarketEasy (区间DP)
- SRM 551 div2 950(DP, 环形+优化)
- Topcoder SRM 144 Div1 550(数学和dp问题求方案数,很有意思)
- SRM 440 WickedTeacher (DP)
- srm 304 div2 1000(环形DP进阶,几何)
- topcoder SRM 654 DIV2 1000 SuccessiveSubtraction2 题解(dp)
- [容斥 DP] Topcoder SRM 498 DIV1 Hard. FoxJumping
- SRM 595 D2 L3:LittleElephantAndXor, dp
- topcoder SRM 666 DIV2 CollectingTokens 树形dp
- TopCoder SRM 666 Div2 Problem 999 - WalkOverATreeDiv2 (树形DP)