zoukankan      html  css  js  c++  java
  • 洛谷 P4728 [HNOI2009]双递增序列

    传送门:https://www.luogu.com.cn/problem/P4728

    题目描述

    这题题面跟数据有点出入,所求并非单调上升序列,而是不下降序列,如 ({2, 3, 3}) 是合法的

    输入格式

    输出格式

    输出 (m) 行, 若第 (i) 行为“好序列”,输出 (Yes!),否则输出 (No!)

    样例

    样例就不给了,大家自己看原题吧。(逃)

    讲解

    这题相当邪乎。。。

    一开始看到这题,同班的大佬们一直认为就是一道 (Dilworth) 定理的水题,于是一发LIS,都不用带优化的就过了。。。

    然而这真的对吗,并不对。。。虽然数据能过,但是他的正确性是无法证明的,事实上有位大佬给出了hack数据,但是我并没看到。。。

    所以说去网上看正解,但是死活理解不了,比如洛谷里大佬的那篇题解,光是那堆初始化就看的我一脸懵。代码也不带打个注释的(明明自己菜还要喷别人)

    所以,还是要靠自(da)己(lao)啊(感恩wzx)。

    从暴力到优化的思路大家可以参考那篇题解,这里只介绍一下正解(我以为的)。

    我们重新定义一下 (f) 数组:

    (f[i][j]=k) 表示,前 (i) 个数中,含有 (a[i]) 的一个集合长度为 (j),不含 (a[i]) 的那个集合的最后一位的最小值,即 (k)

    可能有点绕,但大家一定要好好理解一下,因为这道题完全就是在吃定义,如果无法理解定义的话是没办法做的。

    我们简单的认为含 (a[i]) 的那个集合为第一个集合,另一个为第二个集合。

    理解之后我们来考虑如何转移。

    我这里采用了刷表法,大家可以自己YY填表法。。。

    我们枚举 (i),对于每个 (i),我们考虑 (i+1),选择无非只有两种,一:把 (a[i+1]) 接到含有 (a[i]) 集合后面,二:把 (a[i+1]) 接到另一个集合后面。

    两个集合没有本质区别,所以第二个转移有一个很神奇的交换两个集合的操作,大家注意一下。

    第一个转移:

    (a[i+1]) 接到含有 (a[i]) 的那个集合后面,此时要满足 (a[i+1] >= a[i])

    转移方程为:(f[i+1][j+1]=min(f[i+1][j+1],f[i][j]))

    为什么这么写呢,还是吃定义:我们维护的值是第二个集合的最后一位的最小值,我们在第一个集合后面接东西与他何关?所以直接取min

    第二个转移:

    (a[i+1]) 接到不含 (a[i]) 的那个集合后面,此时要满足 (a[i+1] >= f[i][j])

    转移方程为:(f[i+1][i-j+1]=min(f[i+1][i-j+1],a[i]))

    我想大家可能对这个式子很迷惑,这都什么跟什么啊,我的 (f[i][j]) 去哪里了qwq。

    我们把 (a[i+1]) 接到不含 (a[i]) 的那个集合也就是第二个集合的后面,那么此时,第二个集合变成了对于 (i+1) 而言的第一个集合,因为此时第二个集合最后一位是 (a[i+1]) ,符合我们的第一个集合的定义,他的长度是 (i-j+1),所以我们要更新 (f[i+1][i-j+1]),为什么要用 (a[i]) 来更新呢,因为此时原来的第二个集合变成了第一个集合,自然原来的第一个集合(结尾为 (a[i]))就变成了现在的第二个集合。

    然后这道题就基本结束了,要注意的是初始化 (f[1][1]=-1),因为数据里可能有0,转移时枚举 (j) 从 1 到 (i)

    最后判断 (f[n][n/2]) 是否被更新即可。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    const int maxn = 2000 + 10;
    inline int read(){
    	int s = 0, w = 1;
    	char c = getchar();
    	while(c < '0' || c > '9'){if(c == '-') w = -1; c = getchar();}
    	while(c >= '0' && c <= '9') s = s * 10 + c - '0', c = getchar();
    	return s * w;
    }
    int n, m;
    int a[maxn];
    int f[maxn][maxn];
    int main(){
    	m = read();
    	while(m--){
    		n = read();
    		for(int i = 1; i <= n; i++)
    			a[i] = read();
    		memset(f, 0x3f, sizeof f);
    		f[1][1] = -1;
    		for(int i = 1; i <= n; i++){
    			for(int j = 1; j <= i; j++){
    				if(a[i + 1] >= a[i])
    					f[i + 1][j + 1] = std:: min(f[i + 1][j + 1], f[i][j]);
    				if(a[i + 1] >= f[i][j])
    					f[i + 1][i - j + 1] = std:: min(f[i + 1][i - j + 1], a[i]);
    			}
    		}
    		if(f[n][n / 2] > 1e7) printf("No!
    ");
    		else printf("Yes!
    ");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Apache Maven(三):POM
    Mysql的数据库引擎
    一文搞懂tcp和udp
    OSI七层协议大白话解读
    模型的部分知识及ajax的后端应用
    Django之模型层第二篇:多表操作
    Django基础之模型(models)层之单表及各种查询
    Django基础之视图(views)层、模板层
    Django之路由(urls)层
    创建Django项目基础
  • 原文地址:https://www.cnblogs.com/Zfio/p/13364440.html
Copyright © 2011-2022 走看看