曾有你的森林 尺取法板子题

解决Emiya面临的数学问题,寻找包含特定种类花朵的最短连续序列。使用尺取法算法,通过迭代检查来确定最少数量的花朵,以确保所有目标种类都至少出现一次。

链接:https://ac.nowcoder.com/acm/contest/321/I
来源:牛客网

题目描述

Emiya面前的n朵花按直线排列,一共m种花朵,花的种类用1,2,3…m-1,m的数字进行编号..

Emiya想知道的是,最少连续多少朵花,可以包含前1~k种类花朵每种至少一次.

 

输入描述:

第一行包含一个整数T,表示测试的组数, 1≤T≤10

接下来是T组数据:

每组的第一行包含3个整数n,m,k 其中1 <= n,m <= 10^5,1 <= k <= m

接下来一行包含n个整数,表示按直线排列的n朵花.

输出描述:

每一组数据输出一行,

包含一个整数包含,即为所求的答案.,如果不存在答案 则输出-1

样例

输入

3
5 5 3 
1 2 3 4 5
5 5 3 
1 2 1 2 1
5 4 3 
1 2 4 3 1

输出

3
-1
4

题解

尺取法板子题,不解释了。和 POJ - 3320  这道题方法一样

POJ - 3320 链接 https://vjudge.net/problem/POJ-3320

代码

#include<algorithm>
#include <iostream>
#include<cstring>
#include<map>
#include <cstdio>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,m,k;
        map<int,int> mm;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<n;i++){
            scanf("%d",a+i);
        }
        int ans=1000000;
        int r=0,l=0,cnt=0;
        while(true){
            while(r<n&&cnt<k){
                mm[a[r]]++;
                if(mm[a[r]]==1&&a[r]<=k) cnt++;
                r++;
            }
            if(cnt<k) break;
            ans=min(ans,r-l);
            mm[a[l]]--;
            if(mm[a[l]]==0&&a[l]<=k) cnt--;
            l++;
        }
        if(ans==1000000){
            printf("-1\n");
        }else{
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

提供的引用内容中未涉及C++虚树的板子相关信息。在常见的算法竞赛平台上能找到C++虚树的板子。以下是一些推荐: - **洛谷P2495 [SDOI2011]消耗战**:目要求在一棵树上,给出若干询问,每次询问指定一些关键点,要切断从根节点到所有关键点的路径,求最小的边权和。此问适合用虚树来解决,通过构建虚树,能将每次询问的时间复杂度降低。 - **Codeforces 613D Kingdom and its Cities**:该给出一棵树,多次询问一些点的集合,要判断能否通过删除一些点,使得集合内任意两点不连通,若可以,求最少删除点数。借助虚树可以高效处理每次询问。 ```cpp // 以下是一个简单的虚树构建的伪代码示例 #include <iostream> #include <vector> #include <algorithm> using namespace std; const int MAXN = 100005; vector<int> G[MAXN]; int dep[MAXN], fa[MAXN], top[MAXN], son[MAXN], sz[MAXN]; // 树链剖分相关数组 // 树链剖分初始化 void dfs1(int u, int f) { fa[u] = f; dep[u] = dep[f] + 1; sz[u] = 1; for (int v : G[u]) { if (v == f) continue; dfs1(v, u); sz[u] += sz[v]; if (sz[v] > sz[son[u]]) son[u] = v; } } void dfs2(int u, int t) { top[u] = t; if (son[u]) dfs2(son[u], t); for (int v : G[u]) { if (v == fa[u] || v == son[u]) continue; dfs2(v, v); } } // 求LCA int lca(int u, int v) { while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); u = fa[top[u]]; } return dep[u] < dep[v] ? u : v; } // 构建虚树 vector<int> vt[MAXN]; bool cmp(int u, int v) { return dep[u] < dep[v]; } void build_virtual_tree(vector<int> &key_points) { sort(key_points.begin(), key_points.end(), cmp); vector<int> stk; stk.push_back(1); // 根节点 for (int u : key_points) { if (u == 1) continue; int l = lca(u, stk.back()); while (1) { if (dep[l] >= dep[stk[stk.size() - 2]]) { if (l != stk.back()) { vt[l].push_back(stk.back()); if (l != stk[stk.size() - 2]) stk.push_back(l); } break; } vt[stk[stk.size() - 2]].push_back(stk.back()); stk.pop_back(); } stk.push_back(u); } while (stk.size() > 1) { vt[stk[stk.size() - 2]].push_back(stk.back()); stk.pop_back(); } } int main() { // 这里可以添加读取树的边和关键点的代码 vector<int> key_points = {2, 3, 4}; // 示例关键点 build_virtual_tree(key_points); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值