文章目录

  • 修改数组
  • 倍数问题
  • 斐波那契
  • 距离
  • 剪格子
  • 组合数问题
  • 模拟散列表


修改数组

题目大意
给定一个长度为 蓝桥杯 疑难杂题题解报告_数组 的数组 蓝桥杯 疑难杂题题解报告_疑难杂题_02,数组中有可能有重复出现的整数。
现在小明要按以下方法将其修改为没有重复整数的数组。
小明会依次修改 蓝桥杯 疑难杂题题解报告_疑难杂题_03
当修改 蓝桥杯 疑难杂题题解报告_蓝桥杯_04 时,小明会检查 蓝桥杯 疑难杂题题解报告_蓝桥杯_04 是否在 蓝桥杯 疑难杂题题解报告_数据_06 中出现过。
如果出现过,则小明会给 蓝桥杯 疑难杂题题解报告_蓝桥杯_04 加上 1;如果新的 蓝桥杯 疑难杂题题解报告_蓝桥杯_04 仍在之前出现过,小明会持续给 蓝桥杯 疑难杂题题解报告_蓝桥杯_04 加 1,直到 蓝桥杯 疑难杂题题解报告_蓝桥杯_04 没有在 蓝桥杯 疑难杂题题解报告_数据_06 中出现过。
蓝桥杯 疑难杂题题解报告_数据_12 也经过上述修改之后,显然 蓝桥杯 疑难杂题题解报告_并查集_13 数组中就没有重复的整数了。
现在给定初始的 蓝桥杯 疑难杂题题解报告_并查集_13 数组,请你计算出最终的 蓝桥杯 疑难杂题题解报告_并查集_13 数组。
输入格式
第一行包含一个整数 蓝桥杯 疑难杂题题解报告_数组
第二行包含 蓝桥杯 疑难杂题题解报告_数组 个整数 蓝桥杯 疑难杂题题解报告_疑难杂题_18
输出格式
输出 蓝桥杯 疑难杂题题解报告_数组 个整数,依次是最终的 蓝桥杯 疑难杂题题解报告_疑难杂题_18
数据范围:蓝桥杯 疑难杂题题解报告_蓝桥杯_21
输入样例

5
2 1 1 3 4

输出样例

2 1 3 4 5

蓝桥杯 疑难杂题题解报告_疑难杂题_22表示 蓝桥杯 疑难杂题题解报告_并查集_23 的代表元素
单链表并查集:蓝桥杯 疑难杂题题解报告_疑难杂题_22表示链表中的下一个结点。蓝桥杯 疑难杂题题解报告_并查集_23 所在树的根节点:从蓝桥杯 疑难杂题题解报告_并查集_23开始往右找第一个没有被用过的位置。

#include <cstdio>
using namespace std;
const int maxn = 1e6 + 7;
int fa[maxn],a[maxn];
void init()  //并查集初始化
{
    for(int i = 1; i < maxn; i++) fa[i] = i;
}
int find(int x)  //路径压缩
{
    if(x != fa[x]) fa[x] = find(fa[x]);
    return fa[x];
}
int main()
{
    init();
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        int x;
        scanf("%d",&x);
        x = find(x);  
        printf("%d ",x); 
        fa[x] = x + 1;
    }
    
    return 0;
}

倍数问题

题目大意
众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。
现在小葱给了你 蓝桥杯 疑难杂题题解报告_疑难杂题_27 个数,希望你从这 蓝桥杯 疑难杂题题解报告_疑难杂题_27 个数中找到三个数,使得这三个数的和是 蓝桥杯 疑难杂题题解报告_并查集_29 的倍数,且这个和最大。
数据保证一定有解。
输入格式
第一行包括 2 个正整数 蓝桥杯 疑难杂题题解报告_并查集_30
第二行 蓝桥杯 疑难杂题题解报告_疑难杂题_27 个正整数,代表给定的 蓝桥杯 疑难杂题题解报告_疑难杂题_27 个数。
输出格式
输出一行一个整数代表所求的和。

数据范围:蓝桥杯 疑难杂题题解报告_疑难杂题_33
给定的 蓝桥杯 疑难杂题题解报告_疑难杂题_27 个数均不超过 蓝桥杯 疑难杂题题解报告_疑难杂题_35
输入样例

4 3
1 2 3 4

输出样例

9

蓝桥杯 疑难杂题题解报告_数据_36+贪心
蓝桥杯 疑难杂题题解报告_并查集_37: 表示在 蓝桥杯 疑难杂题题解报告_数组_38 个数中选 蓝桥杯 疑难杂题题解报告_并查集_39 个数 %K 余数是 蓝桥杯 疑难杂题题解报告_疑难杂题_40
属性:值表示最大值
不选 :蓝桥杯 疑难杂题题解报告_数组_41 选: 蓝桥杯 疑难杂题题解报告_数组_42
蓝桥杯 疑难杂题题解报告_数组_43;
优化:
蓝桥杯 疑难杂题题解报告_数组_38 层只用了 蓝桥杯 疑难杂题题解报告_数组_45层 且 蓝桥杯 疑难杂题题解报告_并查集_39 严格小于 蓝桥杯 疑难杂题题解报告_数组_38,并且后面会用到第 蓝桥杯 疑难杂题题解报告_数组_38 层的数据
然后可以把三维 蓝桥杯 疑难杂题题解报告_数据_49 优化成一个二维 蓝桥杯 疑难杂题题解报告_数据_49
将余数相同是值存到同一个数组,然后排序取最值
不断优化取 0 ~ 蓝桥杯 疑难杂题题解报告_疑难杂题_51

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define pb push_back
using namespace std;
const int maxn = 1e3 + 7;
vector<int>rest[maxn];  //存相同余数
int f[4][maxn];

int main()
{
    int n, K, num;
    scanf("%d%d",&n,&K);
    for(int i = 0; i < n; i++)
    {
        scanf("%d",&num);
        rest[num%K].pb(num);  //余数相同的数存到一起
    }
    memset(f, -0x3f, sizeof f);
    f[0][0] = 0;
    
    for(int i = 0; i < K; i++)
    {
        sort(rest[i].begin(),rest[i].end());  
        reverse(rest[i].begin(),rest[i].end());
        
        for(int j = 0; j < 3 && j < rest[i].size(); j++)  //余数相同取前三大的数
        {
            int x = rest[i][j];
            for(int k = 3; k; k--)
            {
                for(int v = 0; v < K; v++)
                    f[k][v] = max(f[k][v],f[k-1][((v-x)%K+K)%K]+x);
            }
        }
    }
    printf("%d\n",f[3][0]);
    return 0;
}

斐波那契

题目大意
斐波那契数列大家都非常熟悉。它的定义是:
蓝桥杯 疑难杂题题解报告_并查集_52
蓝桥杯 疑难杂题题解报告_疑难杂题_53
对于给定的整数 蓝桥杯 疑难杂题题解报告_疑难杂题_27蓝桥杯 疑难杂题题解报告_并查集_55,我们希望求出:
蓝桥杯 疑难杂题题解报告_蓝桥杯_56 的值。
但这个值可能非常大,所以我们把它对 蓝桥杯 疑难杂题题解报告_并查集_57 取模。
但这个数字依然很大,所以需要再对 蓝桥杯 疑难杂题题解报告_并查集_58 求模。
输入格式
输入包含多组数据。
每组数据占一行,包含三个整数 蓝桥杯 疑难杂题题解报告_蓝桥杯_59
输出格式
每组数据输出一个整数,表示答案。
每个数占一行。
数据范围:蓝桥杯 疑难杂题题解报告_并查集_60测试数据不超过100组
输入样例

2 3 5

输出样例

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

using namespace std;

typedef long long ll;

ll p;

ll qmul(ll a, ll b)
{
    ll res = 0;
    while (b)
    {
        if (b & 1) res = (res + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return res;
}

void mul(ll c[][2], ll a[][2], ll b[][2])  // c = a * b
{
    static ll t[2][2];
    memset(t, 0, sizeof t);

    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
            for (int k = 0; k < 2; k ++ )
                t[i][j] = (t[i][j] + qmul(a[i][k], b[k][j])) % p;

    memcpy(c, t, sizeof t);
}

ll F(ll n)
{
    if (!n) return 0;

    ll f[2][2] = {1, 1};
    ll a[2][2] = {
        {0, 1},
        {1, 1},
    };

    for(ll k = n - 1; k; k >>= 1)
    {
        if (k & 1) mul(f, f, a);  // f = f * a
        mul(a, a, a);  // a = a * a
    }

    return f[0][0];
}

ll H(ll m, ll k)  // (F(m - 1) * F(k) - 1) mod F(m)
{
    if (k % 2) return F(m - k) - 1;
    else
    {
        if (k == 0 || m == 2 && m - k == 1) return F(m) - 1;
        else return F(m) - F(m - k) - 1;
    }
}

ll G(ll n, ll m)  // (F(n) - 1) mod F(m)
{
    if (m % 2 == 0)  // m是偶数
    {
        if (n / m % 2 == 0)  // n / m 是偶数
        {
            //cout << n << ' ' << m << ' ' << F(n % m) << endl;
            if (n % m == 0) return F(m) - 1;
            else return F(n % m) - 1;
        }
        else  // n / m 是奇数
        {
            return H(m, n % m);
        }
    }
    else  // m 是奇数
    {
        if (n / m % 2 == 0 && n / 2 / m % 2 == 0)  // n / m 是偶数,n / (2m) 是偶数
        {
            if (n % m == 0) return F(m) - 1;
            else return F(n % m) - 1;
        }
        else if (n / m % 2 == 0 && n / 2 / m % 2)  // n / m 是偶数,n / (2m) 是奇数
        {
            if (m == 2 && n % m == 1) return F(m) - 1;
            else return F(m) - F(n % m) - 1;
        }
        else if (n / m % 2 && n / 2 / m % 2 == 0)  // n / m 是奇数,n / (2m) 是偶数
        {
            return H(m, n % m);
        }
        else  // n / m 是奇数,n / (2m) 是奇数
        {
            if (n % m % 2)
            {
                if (m == 2 && m - n % m == 1) return F(m) - 1;
                else return F(m) - F(m - n % m) - 1;
            }
            else
            {
                return F(m - n % m) - 1;
            }
        }
    }
}

int main()
{
    ll n, m;

    while(~scanf(" %lld%lld%lld",&n,&m,&p))
    {
        ll ans = (G(n + 2, m) % p + p) % p;
        printf("%lld\n",ans);
    }

    return 0;
}

距离

题目大意
给出 蓝桥杯 疑难杂题题解报告_疑难杂题_27 个点的一棵树,多次询问两点之间的最短距离。
注意:
边是无向的。
所有节点的编号是 蓝桥杯 疑难杂题题解报告_数据_62
输入格式
第一行为两个整数 蓝桥杯 疑难杂题题解报告_疑难杂题_27蓝桥杯 疑难杂题题解报告_并查集_55蓝桥杯 疑难杂题题解报告_疑难杂题_27 表示点数,蓝桥杯 疑难杂题题解报告_并查集_55 表示询问次数;
下来 蓝桥杯 疑难杂题题解报告_疑难杂题_67 行,每行三个整数 蓝桥杯 疑难杂题题解报告_疑难杂题_68,表示点 蓝桥杯 疑难杂题题解报告_数组_69 和点 蓝桥杯 疑难杂题题解报告_疑难杂题_70 之间存在一条边长度为 蓝桥杯 疑难杂题题解报告_蓝桥杯_71
再接下来 蓝桥杯 疑难杂题题解报告_并查集_55 行,每行两个整数 蓝桥杯 疑难杂题题解报告_蓝桥杯_73,表示询问点 蓝桥杯 疑难杂题题解报告_数组_69 到点 蓝桥杯 疑难杂题题解报告_疑难杂题_70 的最短距离。
树中结点编号从 1 到 蓝桥杯 疑难杂题题解报告_疑难杂题_27
输出格式
蓝桥杯 疑难杂题题解报告_并查集_55 行,对于每次询问,输出一行询问结果。
数据范围:蓝桥杯 疑难杂题题解报告_数据_78
蓝桥杯 疑难杂题题解报告_并查集_79
输入样例

2 2 
1 2 100 
1 2 
2 1

输出样例

100
100

Tarjan–离线求LCA
在线做法:读一个询问,处理一个,输出一个
离线做法:读完全部询问,再全部处理完,再全部输出

#include <cstdio>
#include <vector>
#include <cstring>
#define PII pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 7;
struct node{
    int to, ne;
    ll val;
};
node edge[maxn<<1];
int head[maxn<<1], tot = 0;
int fa[maxn];
int res[maxn<<2];
vector<PII> query[maxn<<1];   //first:存查询另外一个点 second:存查询编号
int dis[maxn<<1];  //存储每个点到根节点的距离
int st[maxn];  //0:未访问  1:正在访问 2:访问并结束回溯
void add(int x, int y, int w)
{
    edge[++tot].to = y;
    edge[tot].val = w;
    edge[tot].ne = head[x];
    head[x] = tot; 
}
void dfs(int now, int ago)
{
    for(int i = head[now]; i; i = edge[i].ne)
    {
        int to = edge[i].to;
        if(to == ago) continue;  //防止回搜
        dis[to] = dis[now] + edge[i].val;
        dfs(to, now);
    }
}
int find(int x)
{
    if(x != fa[x]) fa[x] = find(fa[x]);
    return fa[x];
}
void tarjan(int now)
{
    st[now] = 1;
    for(int i = head[now]; i; i = edge[i].ne)
    {
        int to = edge[i].to;
        if(!st[to])
        {
            tarjan(to);
            fa[to] = now;  //存父节点
        }
    }
    for(auto it : query[now])
    {
        int to = it.first, id = it.second;
        if(st[to] == 2)   //计算 
        {
            int root = find(to);
            res[id] = dis[now] + dis[to] - (dis[root]<<1);
        }
    }
    st[now] = 2;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1; i < n; i++)
    {
        int x, y; ll w;
        scanf("%d%d%lld",&x,&y,&w);
        add(x, y, w); add(y, x, w);
    }
    for(int i = 1; i <= m; i++)  //查询m次,每次查询的编号
    {
        int x, y;
        scanf("%d%d",&x,&y);
        if(x != y)
        {
            query[x].pb({y, i});
            query[y].pb({x, i});
        }
    }
    
    for(int i = 0; i <= n; i++) fa[i] = i;
    dfs(1,-1);
    tarjan(1);
    for(int i = 1; i <= m; i++) printf("%d\n",res[i]);
    return 0;
}

剪格子

题目大意

如下图所示, 3×3 的格子中填写了一些整数。

蓝桥杯 疑难杂题题解报告_数据_80


我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是 60。

本题的要求就是请你编程判定:对给定的 蓝桥杯 疑难杂题题解报告_并查集_81 的格子中的整数,是否可以分割为两个连通的部分,使得这两个区域的数字和相等。

如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。

如果无法分割,则输出 0。

蓝桥杯 疑难杂题题解报告_蓝桥杯_82

输入格式

第一行包含两个整数 蓝桥杯 疑难杂题题解报告_疑难杂题_83 ,表示表格的宽度和高度。

接下来是 蓝桥杯 疑难杂题题解报告_疑难杂题_27 行,每行 蓝桥杯 疑难杂题题解报告_并查集_55 个正整数,用空格分开。

输出格式

在所有解中,包含左上角的分割区可能包含的最小的格子数目。

如果无法分割,则输出 0。

数据范围:蓝桥杯 疑难杂题题解报告_数组_86格子内的数均在1到10000之间。

输入样例

3 3
10 1 52
20 30 1
1 2 3

输出样例

3
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <unordered_set>
#define rep(i,a,b) for(auto i = (a); i < (b); i++)
#define per(i,a,b) for(auto i = (a); i > (b); i--)
#define pb push_back
using namespace std;
typedef  unsigned long long ULL;
typedef pair<int,int> PII;
const int maxn = 15, base = 131, inf = 0x3f3f3f3f;

int n, m;
int a[maxn][maxn];
bool st[maxn][maxn];
int sum, res = inf;
PII cands[maxn*maxn];
int fa[maxn*maxn];
unordered_set<ULL> hash_table;

int dir[4][2] = {-1, 0, 0, 1, 1, 0, 0, -1};  //方向
int find(int x)  //路径压缩
{
    if(fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}

bool inbound(int x, int l, int r)  //判断位置是否合法
{
    if(x < l || x >= r) return false; //不合法
    return true;
}

bool check_connect(int k)  //检查剩余的是否连通
{
    rep(i, 0, n*m) fa[i] = i;
    int cnt = n*m - k;

    rep(i, 0, n)
        rep(j, 0 , m)
            if(!st[i][j])
            {
                rep(k, 0, 4)
                {
                    int tx = i + dir[k][0], ty = j + dir[k][1];
                    if(!inbound(tx, 0, n) || !inbound(ty, 0, m)) continue;
                    if(st[tx][ty]) continue;

                    int p1 = find(i*m + j),  p2 = find(tx*m + ty);
                    if(p1 != p2)
                    {
                        fa[p1] = p2;
                        cnt--;
                    }
                }
            }
            if(cnt != 1) return false;
            return true;
}

bool check_exists(int k)
{
    static PII bk[maxn*maxn];
    rep(i,0,k) bk[i] = cands[i];
    sort(bk, bk + k);

    ULL x = 0;
    rep(i,0,k)
    {
        x = x*base + bk[i].first + 1;
        x = x*base + bk[i].second + 1;
     }
     if(hash_table.count(x)) return true;
     hash_table.insert(x);
     return false;
}

void dfs(int s, int k)
{
    if(s == sum/2)
    {
        if(check_connect(k)) res = min(res,k);
        return;
    }

    vector<PII> points;
    rep(i, 0, k)
    {
        int x = cands[i].first, y = cands[i].second;
        rep(j, 0 , 4)
        {
            int tx = x + dir[j][0], ty = y + dir[j][1];
            if(!inbound(tx,0,n) || !inbound(ty,0,m)) continue;
            if(st[tx][ty]) continue;

            cands[k] = {tx, ty};
            if(k+ 1 < res && !check_exists(k+1)) points.pb({tx,ty});
        }
    }

    sort(points.begin(), points.end());
    reverse(points.begin(), points.end());
    rep(i, 0, points.size())
    {
        if(!i || points[i] != points[i-1])
        {
            cands[k] = points[i];
            int x = points[i].first, y = points[i].second;
            st[x][y] = true;
            dfs(s + a[x][y], k + 1);
            st[x][y] = false;
        }
    }
}
int main()
{
    scanf("%d%d",&m,&n);
    rep(i, 0, n)
        rep(j, 0, m)
            scanf("%d",&a[i][j]),sum += a[i][j];

    if(sum%2 == 0)
    {
        st[0][0] = true;
        cands[0] = {0, 0};
        dfs(a[0][0], 1);
    }
    if(res == inf) res = 0;
    printf("%d\n",res);
    return 0;
}

组合数问题

题目大意
组合数 蓝桥杯 疑难杂题题解报告_数组_87 表示的是从 蓝桥杯 疑难杂题题解报告_疑难杂题_27 个物品中选出 蓝桥杯 疑难杂题题解报告_并查集_55 个物品的方案数。 
举个例子,从 (1, 2, 3) 三个物品中选择两个物品可以有 (1, 2), (1, 3), (2, 3) 这三种选择方法。 
根据组合数的定义,我们可以给出计算组合数 蓝桥杯 疑难杂题题解报告_数组_87 的一般公式:
蓝桥杯 疑难杂题题解报告_蓝桥杯_91=蓝桥杯 疑难杂题题解报告_数据_92
其中 蓝桥杯 疑难杂题题解报告_数组_93。 
小葱想知道如果给定 蓝桥杯 疑难杂题题解报告_疑难杂题_27, 蓝桥杯 疑难杂题题解报告_并查集_55 和 蓝桥杯 疑难杂题题解报告_蓝桥杯_71,对于所有的 蓝桥杯 疑难杂题题解报告_并查集_97, 蓝桥杯 疑难杂题题解报告_数据_98 有多少对 蓝桥杯 疑难杂题题解报告_疑难杂题_99 满足 蓝桥杯 疑难杂题题解报告_并查集_100 是 蓝桥杯 疑难杂题题解报告_蓝桥杯_71 的倍数。
输入格式
第一行有两个整数 蓝桥杯 疑难杂题题解报告_并查集_102 ,其中 蓝桥杯 疑难杂题题解报告_并查集_103 代表该测试点总共有多少组测试数据,蓝桥杯 疑难杂题题解报告_蓝桥杯_71 的意义见问题描述。
接下来 蓝桥杯 疑难杂题题解报告_并查集_103 行每行两个整数 蓝桥杯 疑难杂题题解报告_疑难杂题_106 ,其中 蓝桥杯 疑难杂题题解报告_疑难杂题_106 的意义见问题描述。
输出格式
蓝桥杯 疑难杂题题解报告_并查集_103 行,每行一个整数代表所有的 蓝桥杯 疑难杂题题解报告_并查集_97, 蓝桥杯 疑难杂题题解报告_数据_98 有多少对 蓝桥杯 疑难杂题题解报告_疑难杂题_99 满足 蓝桥杯 疑难杂题题解报告_并查集_100 是 蓝桥杯 疑难杂题题解报告_蓝桥杯_71 的倍数。
数据范围:蓝桥杯 疑难杂题题解报告_数据_114
输入样例

1 2
3 3

输出样例

1

打表求组合数,过百分之90的数据

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 7;
ll f[maxn][maxn];
int mod;
void init()
{
    for(int i = 0; i < maxn; i++)
        for(int j = 0; j <= i; j++)
            if(j == 0) f[i][j] = 1;
            else f[i][j] = (f[i-1][j] + f[i-1][j-1])%mod;
}
int main()
{
    int n, m, t;
    scanf("%d%d",&t,&mod);
    init();
    while(t--)
    {
        ll res = 0;
        scanf(" %d%d",&n,&m);
        for(int i = 0; i <= n; i++)
        {
            int t = min(i,m);
            for(int j = 0; j <= t; j++)
                if(f[i][j]%mod == 0) res++;
        }
        printf("%d\n",res);
    }
    return 0;
}

正解打表求组合数+前缀和

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 7;
ll f[maxn][maxn], mod;
int s[maxn][maxn];
void init()
{
    for(int i = 0; i < maxn; i++)
        for(int j = 0; j <= i; j++)
        {
            if(j == 0) f[i][j] = 1;
            else f[i][j] = (f[i-1][j] + f[i-1][j-1])%mod;
            
            if(!f[i][j]) s[i][j] = 1;
        }
            
    for(int i = 0; i < maxn; i++)
    {
        for(int j = 0; j < maxn; j++)
        {
            if(i) s[i][j] += s[i-1][j];
            if(j) s[i][j] += s[i][j-1];
            if(i && j) s[i][j] -= s[i-1][j-1];
        }
    }
}
int main()
{
    int n, m, t;
    scanf("%d%d",&t,&mod);
    init();
    while(t--)
    {
        scanf("%d%d",&n,&m);
        printf("%d\n",s[n][m]);
    }
    return 0;
}

模拟散列表

题目大意
维护一个集合,支持如下几种操作:

  1. 蓝桥杯 疑难杂题题解报告_数组_115,插入一个数蓝桥杯 疑难杂题题解报告_并查集_116
  2. 蓝桥杯 疑难杂题题解报告_数据_117,询问数 蓝桥杯 疑难杂题题解报告_并查集_116 是否在集合中出现过;
    现在要进行 蓝桥杯 疑难杂题题解报告_疑难杂题_119

输入格式
第一行包含整数 蓝桥杯 疑难杂题题解报告_数组,表示操作数量。
接下来 蓝桥杯 疑难杂题题解报告_数组 行,每行包含一个操作指令,操作指令为 蓝桥杯 疑难杂题题解报告_并查集_122蓝桥杯 疑难杂题题解报告_并查集_123中的一种。
输出格式
对于每个询问指令 蓝桥杯 疑难杂题题解报告_数组_124,输出一个询问结果,如果 蓝桥杯 疑难杂题题解报告_数组_69 在集合中出现过,则输出 蓝桥杯 疑难杂题题解报告_疑难杂题_126,否则输出 蓝桥杯 疑难杂题题解报告_疑难杂题_127
每个结果占一行。

数据范围:蓝桥杯 疑难杂题题解报告_数据_128
输入样例

5
I 1
I 2
I 3
Q 2
Q 5

输出样例

Yes
No

复杂的数据映射到小范围的数
时间复杂度O(n)
1.插入操作
(1)先找到槽
(2)赋值
(3)ne指针指向后面
(4)插入点上一个位置的数的指针指向当前位置

#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1e5 + 7;
struct Node{
    int val;  //权值
    int ne;  //指针
};
int tot;
int head[maxn];
Node node[maxn];

int Insert(int x)  //插入
{
   int k = (x%maxn + maxn)%maxn;
   node[++tot].val = x;  //存点
   node[tot].ne = head[k];  //ne指针指向后面
   head[k] = tot; //指向当前位置
}

bool find(int x)  //查询
{
    int k = (x%maxn + maxn)%maxn;
    for(int i = head[k]; i; i = node[i].ne)
        if(node[i].val == x) return true;
    return false;
}

int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        int num;
        char op;
        scanf(" %c%d",&op,&num);
        if(op == 'I') Insert(num);
        else
        {
            if(find(num)) printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}