杂题之----并查集和DP(蓝桥)

杂题之----并查集和DP

1.修复数组:

问题:

给定一个长度为 NN 的数组 A=[A1,A2,⋅⋅⋅AN]数组中有可能有重复出现的整数。

现在小明要按以下方法将其修改为没有重复整数的数组。

小明会依次修改 A2,A3,⋅⋅⋅,AN。

当修改 Ai 时,小明会检查 Ai 是否在 A1∼Ai−1 中出现过。

如果出现过,则小明会给 Ai 加上 1;如果新的 Ai 仍在之前出现过,小明会持续给 Ai 加 1,直到 Ai 没有在 A1∼Ai−1 中出现过。

当 AN也经过上述修改之后,显然 A数组中就没有重复的整数了。

现在给定初始的 A 数组,请你计算出最终的 A 数组。

数据范围

1≤N≤105
1≤Ai≤106

思路:

由于Ai的数据范围是1e6,不是很大,因此可以考虑用并查集,并查集的思想是每个数刚开始都指向自己的根节点,就是自己,当这个数被使用了之后,就让他的父节点指向下一个根节点。这样每次查根节点的时候都是没用过的数。查询的时候,进行路径压缩,能大大减小查询时间。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FeAjGnuD-1584618349588)(C:\Users\15209\Pictures\博客\bing.jpg)]

代码:

#include <cstdio>

using namespace std;

const int N=1100010;

int p[N];

int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<N;i++) p[i]=i;
    
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        int t=find(x);
        printf("%d ",t);
        p[t]=t+1;
    }
    
    return 0;
}

2.倍数问题

题目:

现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。

扫描二维码关注公众号,回复: 10166881 查看本文章

数据范围

1≤n≤105
1≤K≤103
给定的 n 个数均不超过 108

思路:

这是一道组合问题(选择问题),其实就是背包问题,有三个限制条件:

1.从n个数中选数

2.选3个数

3.这三个数的和是k的倍数

根据三个限制条件,可以确定状态数组为三维的,f(i,j,k);从前i个数中选j个,且%K=k。分类的话,我们可以根据第i个数选和不选来分类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ofLkprSo-1584618349591)(C:\Users\15209\Pictures\博客\bing2.jpg)]

但是如果不做优化还是可能会超时,这里我们就根据贪心来做优化,贪心的思路就是我们和要取最大,对于余数想同的数,我们只需要保留最后三个最大的。因此代码如下:

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;
const int N=1010;

int f[4][N];
vector<int> a[N];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        int x;
        scanf("%d",&x);
        a[x%m].push_back(x);
    }
    
    memset(f,-0x3f,sizeof f);
    f[0][0]=0;
    for(int i=0;i<m;i++)
    {
        sort(a[i].begin(),a[i].end());
        reverse(a[i].begin(),a[i].end());
        
        
        for(int u=0;u<3 && u<a[i].size();u++)
        {
            int x=a[i][u];
            for(int j=3;j>=1;j--)
                for(int k=0;k<m;k++)
                     f[j][k]=max(f[j][k],f[j-1][((k-x)%m+m)%m]+x);
            
        }
           
        
    }
    
    printf("%d",f[3][0]);
    return 0;
    
}
发布了75 篇原创文章 · 获赞 8 · 访问量 1250

猜你喜欢

转载自blog.csdn.net/qq_40905284/article/details/104974884
今日推荐