【浮*光】 #noip模拟# 2018.08.29

T1 seq

【问题描述】

给一个长度为 𝑁 的序列 𝐴 ,你可以把 𝐴 中的 0 改成其他的数字.

(正数,负数, 0均可,不同的 0 可以改成不同的而数字),

要求修改后 𝐴 最长上升子序列的长度最大.输出这个长度.

【输入格式】

第一行一个 𝑁 ,表示数字的个数.

接下来 𝑁 个数字,第 𝑖 个表示 𝐴𝑖.

【输出格式】

一个数字,答案.

【数据规模】

对于 20% 的数据, 𝑁 ≤ 20, 𝐴𝑖 ≥ 1 .

对于 60% 的数据, 𝑁 ≤ 1000 .

对于另 10% 的数据, 𝐴𝑖 ≤ 10 .

对于 100% 的数据, 𝑁 ≤ 10^5, 0 ≤ 𝐴𝑖 ≤ 10^9.


【题目解答】

题意为:给一个序列,你可以把序列中的 0 随意修改,要求最大化 LIS 的长度.

记 𝑆𝑖 表示前 𝑖 个数字中 0 的个数,可以写出一个很显然的 dp.

𝑑𝑝[𝑖]= max (𝑗<𝑖,𝑎𝑗<𝑎𝑖) { 𝑑𝑝[𝑗] + min{ 𝑎𝑖 − 𝑎𝑗 − 1, 𝑆𝑖 − 𝑆𝑗 } }。

时间复杂度 𝑂(𝑁^2) .使用数据结构可以做到 𝑂(𝑁 log2𝑁 ).

然后只需注意到一定存在一种最优解使得所有的 0 都被加了进来,

所以 0 的个数加上对所有非 0 数的 𝑎𝑖 − 𝑆𝑖 算 LIS 的长度就是答案.

时间复杂度 𝑂(𝑁 log 𝑁 ) .

#include <cmath>
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

/*【seq】
给一个长度为𝑁的序列𝐴,可以把0改成其他的数字。
-----> 正数,负数,0均可,不同的0可以改成不同的数字。
要求修改后𝐴最长上升子序列的长度最大。输出这个长度。 */

deque<int> dq; //双端队列:支持在两端高效地插入删除元素的连续线性存储空间

int main(){
    int n,num0=0; cin >> n;
    dq.push_front(INT_MIN); //队头初始化为-inf
    for(int i = 0; i < n; i++) {
        int t; cin >> t;
        if(t == 0) {
            num0++; dq.push_front(INT_MIN);
        } else{
            int cnt=lower_bound(dq.begin(),dq.end(),t-num0)-dq.begin()-1;
            int best=cnt+1;
            if(best==dq.size()) dq.push_back(INT_MAX);
            dq[best]=min(dq[best],t-num0);
        }
    }
    cout << dq.size()-1 << endl;
    return 0;
}

 

T2 paint

【问题描述】

给出一张 𝑁 个点, 𝑀 条边的图 𝐺(𝑉, 𝐸 ) ,点的标号是 0 到 𝑁 − 1 .

对于每个非空点集 𝑆 (共有 2^𝑁−1 个),

定义 𝑓 (𝑆 ) = min{𝑘|𝑆存在𝑘 −染色方案},要求对每个 𝑆 都计算 𝑓 (𝑆 ) .

定义一个点集 𝑆 的 𝑘−染色方案是指对所有的 𝑢 ∈ 𝑆 确定一个 𝐿𝑢 ∈ [1, 𝑘 ] ,

使得所有 𝑢 ∈ 𝑆, 𝑣 ∈ 𝑆, (𝑢, 𝑣) ∈ 𝐸 的点对 (𝑢, 𝑣) 有 𝐿𝑢 != 𝐿𝑣.

【输入格式】

第一行一个数 𝑁 ,表示点数.

接下来 𝑁 行,每行一个长度为 𝑁 的 01 串,表示邻接矩阵.

数据保证合法.

【输出格式】

一个数字,答案.

【数据规模】

对于 30% 的数据, 𝑁 ≤ 4 .

对于 60% 的数据, 𝑁 ≤ 10 .

对于 100% 的数据, 𝑁 ≤ 18 .


【题目解答】

给一张无向图,要求对于每个非空点集都计算色数.𝑁 ≤ 18.

 

T3 trie

【问题描述】

有 𝑁 个串,有 𝑄 个询问,每次询问用 𝑙, 𝑟 描述,

表示询问编号在 [𝑙, 𝑟] 中的串有多少个不同的前缀.

【输入格式】

第一行一个数字 𝑁 ,表示串的个数.

接下来 𝑁 行,每行一个串.

接下来一个 𝑄 ,表示询问次数.

接下来 𝑄 行,每行两个数 𝑙0, 𝑟0,表示询问区间,

为了强制在线,你需要做以下操作:

𝑙 = (𝑙0 + 𝑙𝑎𝑠𝑡𝑎𝑛𝑠) 𝑚𝑜𝑑 𝑛 + 1

𝑟 = (𝑟0 + 𝑙𝑎𝑠𝑡𝑎𝑛𝑠) 𝑚𝑜𝑑 𝑛 + 1

𝑖𝑓 ( 𝑙 > 𝑟 )  𝑠𝑤𝑎𝑝( 𝑙 , 𝑟 )

𝑙𝑎𝑠𝑡𝑎𝑛𝑠 表示上一次询问的答案,初始为 0 .

【输出格式】

𝑄 行,每行一个数表示答案.

【数据规模】


【题目解答】

有 𝑁 个串,有 𝑄 次询问,每次把一个区间里的串插到 trie 里,问有多少个节点.

算法一

把所有的串拉进去建一个 trie ,每次询问就变成求关键点到根路径并的大小,

把关键点按照 dfs 排序后就变成深度和减排序后相邻两点 lca 的深度和.

考虑维护后者,把序列分块,处理出块到块之间后者的值,

这个可以用主席树解决,询问也类似.

时间复杂度 𝑂((𝑁 + 𝑄)√𝑁 log 𝑁 ) ,期望得分 70 分.

算法二

把序列的前缀 hash 以后排成一排,

问题就变成了区间 [𝑙, 𝑟] 中有多少个不同的数字.

用 𝑝𝑟𝑒 𝑖 表示 𝑖 前面一个和 𝐴𝑖 相同的位置,

问题就变成求 𝑝𝑟𝑒 𝑖 < 𝑙, 𝑙 ≤ 𝑖 ≤ 𝑟的 𝑖 的个数,

这是一个二维数点问题,直接主席树即可.

 

 

                                               ——时间划过风的轨迹,那个少年,还在等你。

 

posted @ 2018-08-29 16:03  花神&缘浅flora  阅读(436)  评论(0编辑  收藏  举报