POJ 3670 Eating Together (①O(n)的dp,②最长字段和)

题目大意:找到队列中不符合非升(降)序趋势的编号个数,

分别判断升序跟降序的个数,最后取最小。

两种方法:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

#define maxn 30005

int n;
int cow[maxn];
int f[maxn][5];

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &cow[i]);
    memset(f, 0, sizeof(f));
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= 3; j++)
        {
            f[i][j] = f[i - 1][1];
            for (int k = 2; k <= j; k++)
                f[i][j] = min(f[i][j], f[i - 1][k]);
            if (cow[i] != j)
                f[i][j]++;
        }
    }

    int ans = n;
    for (int i = 1; i <= 3; i++)
        ans = min(ans, f[n][i]);

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= 3; j++)
        {
            f[i][j] = f[i - 1][3];
            for (int k = 2; k >= j; k--)
                f[i][j] = min(f[i][j], f[i - 1][k]);
            if (cow[i] != j)
                f[i][j]++;
        }
    }
    for (int i = 1; i <= 3; i++)
        ans = min(ans, f[n][i]);
    printf("%d\n", ans);

    return 0;
}
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int sup=30005;
int LDS[sup];//不升
int LIS[sup];//不降
int dp[sup];
int n;
int bsearch(int beg,int end,int p)
{
    int mid;
    while(beg<=end)
    {
        mid=(beg&end)+((beg^end)>>1);
        if(dp[mid]<=p)
            beg=mid+1;
        else if(dp[mid]>p)
            end=mid-1;
    }
    return beg;
}
int lis()
{
    int i;
    int top=-1;
    for(i=0;i<n;++i)
    {
        if(dp[top==-1?0:top]<=LIS[i])
            dp[++top]=LIS[i];
        else if(dp[top==-1?0:top]>LIS[i])
            dp[bsearch(0,top,LIS[i])]=LIS[i];
    }
    return n-top-1;
}
int lds()
{
    int i,top=-1;
    for(i=0;i<n;++i)
    {
        if(dp[top==-1?0:top]<=LDS[i])
            dp[++top]=LDS[i];
        else if(dp[top==-1?0:top]>LDS[i])
            dp[bsearch(0,top,LDS[i])]=LDS[i];
    }
    return n-top-1;
}
int main()
{
    int i;
    scanf("%d",&n);
    for(i=0;i<n;++i)
    {
        scanf("%d",&LIS[i]);
        LDS[n-i-1]=LIS[i];
    }
    int ans=lis();
    fill(dp,dp+sup,0);
    int t=lds();
    ans=ans<t?ans:t;
    if(ans!=-1)
    printf("%d\n",ans);
    else
        printf("0\n");
    return 0;
}
时间: 2024-10-08 14:19:42

POJ 3670 Eating Together (①O(n)的dp,②最长字段和)的相关文章

POJ 3670 Eating Together 二分单调队列解法O(nlgn)和O(n)算法

本题就是一题LIS(最长递增子序列)的问题.本题要求求最长递增子序列和最长递减子序列. dp的解法是O(n*n),这个应该大家都知道,不过本题应该超时了. 因为有O(nlgn)的解法. 但是由于本题的数据特殊性,故此本题可以利用这个特殊性加速到O(n)的解法,其中的底层思想是counting sort分段的思想.就是如果你不会counting sort的话,就很难想出这种优化的算法了. O(nlgn)的单调队列解法,利用二分加速是有代表性的,无数据特殊的时候也可以使用,故此这里先给出这个算法代码

POJ 3670 Eating Together

Description The cows are so very silly about their dinner partners. They have organized themselves into three groups (conveniently numbered 1, 2, and 3) that insist upon dining together. The trouble starts when they line up at the barn to enter the f

POJ 3670 Eating Together (DP,LIS)

题意:给定 n 个数,让你修改最少的数,使得它变成一个不下降或者不上升序列. 析:这个就是一个LIS,但是当时并没有看出来...只要求出最长LIS的长度,用总数减去就是答案. 代码如下: #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <s

POJ 3670 Eating Together 二分解法O(nlgn)和O(n)算法

本题就是一题LIS(最长递增子序列)的问题.本题要求求最长递增子序列和最长递减子序列. dp的解法是O(n*n),这个应该大家都知道.只是本题应该超时了. 由于有O(nlgn)的解法. 可是因为本题的数据特殊性.故此本题能够利用这个特殊性加速到O(n)的解法.当中的底层思想是counting sort分段的思想.就是假设你不会counting sort的话,就非常难想出这样的优化的算法了. O(nlgn)的利用单调队列性质的解法,利用二分加速是有代表性的,无数据特殊的时候也能够使用.故此这里先给

POJ 3670 &amp;&amp; POJ 3671 (dp)

最长不下降子序列的应用嘛.两题都是一样的. POJ 3670:求给定序列按递增或递减排列时,所需改变的最小的数字的数目. POJ 3671:求给定序列按递增排列时,所需改变的最小的数字的数目. 思路就是求最长不下降子序列,然后剩下的就是需要改变的字母. 最长不下降子序列:(我之前有写过,不懂请戳)http://blog.csdn.net/darwin_/article/details/38360997 POJ 3670: #include<cstdio> #include<cstring

POJ 3254 Corn Fields //入门状压dp

Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7578   Accepted: 4045 Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yumm

HDU 1087 &amp;&amp; POJ 2533(DP,最长上升子序列).

~~~~ 两道题的意思差不多,HDU上是求最长上升子序列的和,而POJ上就的是其长度. 貌似还有用二分写的nlogn的算法,不过这俩题n^2就可以过嘛.. ~~~~ 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1087 http://poj.org/problem?id=2533 ~~~~ HDU1087: #include<cstdio> #include<cstring> #include<algorithm> #

POJ 2411 Mondriaan&#39;s Dream(状压DP)

http://poj.org/problem?id=2411 求一个n*m矩阵用1*2方块去填满的情况有几种 思路:状压dp,先预处理那些状态之间能互相到达,情况就几种,上一个两个1,下一个状态也两个1,上一个为0,下一个必须为1,还有一种是上一个为1,下一个为0的情况 然后就一层层往后递推即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int

TOJ 2294 POJ 3286 How many 0&#39;s? 数位dp

http://acm.tju.edu.cn/toj/showp2294.html http://poj.org/problem?id=3284 题外话:集训结束,回学校了.在宿舍看了这题,没什么好想法,去洗澡了.转了两个澡堂都特么没开..倒是在路上把这题想了.用回自己的电脑,不得不说苹果的字体渲染,真心高一个等级. 题意:给定两个数a和b,从a写到b,问一共写了多少个0. 分析:当然先转化为求0..a写多少个0.网上有更简单的做法,就是枚举每位作为0,则如果这一位本来是0,左边取1..a-1(不