zoukankan      html  css  js  c++  java
  • [bzoj3126][USACO2013]Photo_动态规划_单调队列

    Photo bzoj-3126

    题目大意:给你一个n长度的数轴和m个区间,每个区间里有且仅有一个点,问最多能有多少个点。

    注释:$1le n le 2cdot 10^5$,$1le mle10^5$。

    想法:开始和GXZlegend在那里贪心。贪了挺久发现几乎所有的贪心策略都会被卡,此题被当做毒瘤题。然后上bz上找题解发现了新大陆??

      这题是一个dp。

      状态:dp[i]表示第i个位置必须放点,最多能在前i个位置放多少点。

      转移:我们记录几个事儿。首先,R[i]表示所有区间中包含i且左端点最大的区间的左端点坐标。L[i]表示所有取件中右端点在i左侧且左端点最大的左端点坐标。关于L和R的更新显然是容易的,我们只需要再每加进来的区间里更新即可。然后转移方程就是f[i] = max { f[j] } + 1 ( L[i]<=j<=R[i] ) 。这个过程可以用单调队列来优化。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define N 200003
    using namespace std;
    int n,m,L[N],R[N];
    int head,tail,q[N],f[N];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n+1;i++) R[i]=i-1;
    	for(int i=1;i<=m;i++)
    	{
    		int x,y; scanf("%d%d",&x,&y);
    		R[y]=min(R[y],x-1);
    		L[y+1]=max(L[y+1],x);
    	}
    	for(int i=n;i>=1;i--) R[i]=min(R[i+1],R[i]);
    	for(int i=2;i<=n+1;i++) L[i]=max(L[i-1],L[i]);
    	int j=1; head=tail=1; q[1]=0;
    	for(int i=1;i<=n+1;i++)
    	{
    		while(j<=R[i]&&j<=n)
    		{
    			if(f[j]==-1)
    			{
    				j++;
    				continue;
    			}
    			while(f[j]>f[q[tail]]&&head<=tail) tail--;
    			q[++tail]=j;
    			j++;
    		}
    		while(q[head]<L[i]&&head<=tail) head++;
    		if(head<=tail) f[i]=f[q[head]]+(i!=n+1?1:0);
    		else f[i]=-1;
    	}
    	printf("%d
    ",f[n+1]);
    }
    

      小结:贪心显然的题大部分好像都不是贪心,因为dp实在是太tm强了。

  • 相关阅读:
    Silverlight之各种线程的操作
    MVVM之Event and Command
    Silverlight之DescriptionViewer
    MVVM之Validation
    蚁群算法(C语言实现)
    最小生成树的prim算法
    关于HashMap、LinkedHashMap与TreeMap
    Slope One :简单高效的协同过滤算法(Collaborative Filtering)——转
    java中使用匿名类重写
    Session学习:防止用户重复提交表单(单态设计模式原子设计模式+MD5技术&Base64算法)
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9026151.html
Copyright © 2011-2022 走看看