首页 > 其他分享 >暑期思维训练

暑期思维训练

时间:2023-07-09 11:34:34浏览次数:28  
标签:思维 训练 10 int 暑期 times dep 数组 集合

LIS or Reverse LIS?

设一个长为 \(n\) 的整数序列 \(a\) 是 \(\{a_1,a_2,a_3,\cdots,a_n\}\),那么 \(a'\) 表示 \(\{a_n,a_{n-1},a_{n-2},\cdots,a_1\}\),\(\operatorname{LIS}(a)\) 表示 \(a\) 的最长严格上升子序列的长度。

现在给定 \(a\) 数组,请你将 \(a\) 数组重新排列,使得重排后的 \(\min(\operatorname{LIS}(a),\operatorname{LIS}(a'))\) 最大。

输入 \(t\) 组数据,每组数据先输入 \(n\) ,然后输入 \(n\) 个整数,所有 \(n\) 之和不超过 \(2 \times 10^5\)。

输出 \(t\) 行,每行一组数据的答案,按输入顺序输出。

题解

  • 容易发现当序列\(a\)被重排后形成单峰时答案一定最大
  • 那么我们考虑如何将序列\(a\)以最优的形式重排成单峰
  • 如果一个数\(x\)出现了两次,那么放在单峰的同一侧一定对答案没有贡献,所有我们可以\(x\)放在两侧,答案贡献 \(+ 1\),如果\(x\)出现2次以上,因为是严格上升,所以不管我们把\(x\)多余的部分放在哪一侧,都不会产生新的贡献
  • 如果说出现1次的数有\(x\)个,且\(x\)为奇数,我们可以将其中一个点作为单峰点,贡献为\(\frac{x + 1}{2}\)
  • 如果说出现1次的数有\(x\)个,且\(x\)为偶数,那么没有单峰点,贡献为\(\frac{x}{2}\)
const int N = 2e5 + 10, M = 4e5 + 10;

int n;
int a[N];
map<int, int> mp;

void solve()
{
    cin >> n;
    mp.clear();
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i];
        mp[a[i]]++;
    }
    int ans = 0;
    int sum = 0;
    for (auto [x, y] : mp)
    {
        if (y >= 2)
            ans++;
        else
            sum++;
    }
    cout << ans + (sum + 1) / 2 << endl;
}

Tokitsukaze and Strange Inequality

给一个长度为 \(n\) 的排列,求有多少个四元组 \((a,b,c,d)\) 满足 \(a<b<c<d\) 和 \(p_a<p_c\)、\(p_b>p_d\)。

\(n\le 5000\)

题解:前缀和dp / 树状数组

  • 首先我们不妨枚举\(b,c\),然后设\([1,b-1]\)中\(x\)个数比\(p_c\)小,\([c + 1,n]\)中有\(y\)个数比\(p_b\)小,那么对答案的贡献为\(x \times y\),所以我们需要求出\(x\)和\(y\)
  • 解法1:
  • 我们不妨预处理\(cnt[i][j]\),代表从第\(i\)个数到第\(j\)个数之间,有多少个数比\(p_i\)小
  • 然后我们枚举\(b,c\),并利用前缀和思想求出\(x\)和\(y\)即可
  • 复杂度:\(O(n ^ 2)\)
  • 解法2:
  • 我们可以开两个树状数组预处理出\(x,y\),复杂度\(O(nlogn)\)
  • 然后我们枚举\(b,c\),并利用前缀和思想求出\(x\)和\(y\)即可,复杂度\(O(n ^ 2)\)
const int N = 5e3 + 10, M = 4e5 + 10;

int n;
int a[N];
int c[N];
int Lcnt[N][N], Rcnt[N][N];

void solve()
{
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            Lcnt[i][j] = Rcnt[i][j] = 0;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    for (int i = 1; i <= n; ++i)
    {
        int sum = 0;
        for (int j = i + 1; j <= n; ++j)
        {
            if (a[j] < a[i])
                sum++;
            Rcnt[i][j] = sum;
        }
    }
    for (int i = 1; i <= n; ++i)
    {
        int sum = 0;
        for (int j = i - 1; j >= 1; --j)
        {
            if (a[j] < a[i])
                sum++;
            Lcnt[i][j] = sum;
        }
    }
    ll ans = 0;
    for (int i = 1; i <= n; ++i) // 枚举b
    {
        for (int j = i + 1; j <= n; ++j) // 枚举c
        {
            ans += 1LL * (Rcnt[i][n] - Rcnt[i][j]) * (Lcnt[j][1] - Lcnt[j][i]);
        }
    }
    cout << ans << endl;
}

Infected Tree

Infected Tree

给定一棵以\(1\) 号节点为根的二叉树,总节点个数为 \(n\)。

现在 \(1\) 号节点感染了病毒,病毒每一回合都会去感染与该节点直接相连的节点,而你在这一回合里可以选择删除任意一个没有被病毒感染(尚未被删除)的点,这样就断开了它与其直接相连的点得关系.

询问最多可以有多少不被病毒感染的点,被删除的点不算做不被病毒感染的点

题解:树形\(dp\) + 思维

  • 容易发现病毒传染的路径一定是一条链,我们只要求出链长和被删除点的数量之和的最小值即可
  • 一种情况病毒传染到叶子节点时结束,设节点的深度为\(dep\),链长为\(dep\),被删除的点数量为\(dep - 1\)
  • 另一种情况病毒传染到只有一个儿子的节点结束,链长为\(dep\),被删除的点的数量为\(dep\)
const int N = 3e5 + 10, M = 4e5 + 10;

int n;
vector<int> g[N];
int dep[N];
int mi = INF;

void dfs(int u, int par)
{
    dep[u] = dep[par] + 1;
    int cnt = 0;
    for (auto v : g[u])
    {
        if (v == par)
            continue;
        cnt++;
        dfs(v, u);
    }
    if (cnt == 0)
        mi = min(mi, 2 * dep[u] - 1);
    else if (cnt == 1)
        mi = min(mi, 2 * dep[u]);
}

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        dep[i] = 0;
        g[i].clear();
    }
    for (int i = 1, u, v; i <= n - 1; ++i)
    {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    mi = INF;
    dfs(1, 0);
    cout << n - mi << endl;
}

AND Sequences

一个 \(n\) 个数的非负数组如果 \(\forall i\in\left[1,n\right)\) ,有 \(a_1\) & \(a_2\) & \(……\) & \(a_i = a_{i+1}\) & \(a_{i+2}\) & \(……\) & \(a_n\) ,那么这个数组叫做 \(“\) 好的数组 \(”\) 。其中&表示按位与。

给定一个长度为 \(n\) 的数组,求这个数组有多少种排列是 \(“\) 好的数组 \(”\) 。因为这个数字可能很大,所以输出结果模 \(10^9+7\) 即可。

两个排列不同,指这个排列有一个位置的数与其他排列的这一位置的数的下表不同。

  • $ s_1 = s_2 : & : s_3 : & : s_4 : & : s_5 = 0 $ ,
  • $ s_1 : & : s_2 = s_3 : & : s_4 : & : s_5 = 0 $ ,
  • $ s_1 : & : s_2 : & : s_3 = s_4 : & : s_5 = 0 $ ,
  • $ s_1 : & : s_2 : & : s_3 : & : s_4 = s_5 = 0 $ .

题解

  • 我们对于\(a_1 = a_2 \&...\&a_m\)和\(a_1\&a_2...\&a_{m-1}=a_m\)两边同时分别&上\(a_1\)和\(a_m\)
  • 容易发现\(a_1 = a_1\&a_2 \&...\&a_m=a_m\)
  • 那么只要我们找到这样的\(a_1\)和\(a_m\),那么\(a_1\&...\&a_i=a_{i+1}\&...\&a_m\)一定成立
  • 对于答案的贡献我们只要组合计数一下即可
const int N = 2e5 + 10, M = 4e5 + 10;

int n;
int a[N];
int fac[N];

void init()
{
    fac[0] = 1;
    for (int i = 1; i <= n; ++i)
        fac[i] = fac[i - 1] * i % mod;
}

void solve()
{
    cin >> n;
    init();
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    int sum = a[1];
    for (int i = 2; i <= n; ++i)
        sum &= a[i];
    int cnt = 0;
    for (int i = 1; i <= n; ++i)
    {
        if (a[i] == sum)
            cnt++;
    }
    cout << cnt * (cnt - 1) % mod * fac[n - 2] % mod << endl;
}

Plus and Multiply

有一个无穷大的正整数集合 \(S\),该集合按下面所述方法生成:

  • 数字 \(1\) 在集合 \(S\) 中。

  • 若数字 \(x\) 在该集合中,那么数 \(x \times a\) 和数 \(x+b\) 均在集合 \(S\) 中。(其中 \(a\) 与 \(b\) 为给定常数)

现在给出数 \(n,a,b\),请判断 \(n\) 是否在集合 \(S\) 中(此处给出的 \(a\) 与 \(b\) 就是上述集合生成方法中的 \(a\) 和 \(b\)),若在请输出 Yes,否则输出 No。多组数据。

令数据组数为 \(t\),那么有 \(1 \leq t \leq 10^5\),\(1 \leq n,a,b \leq 10^9\)。

题解

  • 对于集合中的一个数\(x\)
  • 我们观察$x \times a + b \(和\)(x + b)\times a$
  • 我们发现\((x + b) \times a = x \times a + a \times b\),也就是说对于先加\(b\)再乘\(a\),我们可以转换为先乘\(a\)然后加上\(a\)个\(b\)
  • 也就是这样我们可以一直进行乘法\(\times a\)操作,然后再进行\(+b\)操作
  • 这样的话集合中数字一定可以表示成\(a^x + y\times b\)
  • 那么我们只要枚举\(x\)即可判断\(n\)是否在集合中
  • 时间复杂度为\(O(log_a^n)\)
  • 注意当\(a = 1\) 或者\(b = 1\) 的时候需要特判
const int N = 2e5 + 10, M = 4e5 + 10;

void solve()
{
    int n, a, b;
    cin >> n >> a >> b;
    if (a == 1)
    {
        if (n % b == 1 || b == 1)
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
        return;
    }
    int sum = 1;
    while (sum <= n)
    {
        if ((n - sum) % b == 0)
        {
            cout << "Yes" << endl;
            return;
        }
        sum *= a;
    }
    cout << "No" << endl;
}

标签:思维,训练,10,int,暑期,times,dep,数组,集合
From: https://www.cnblogs.com/Zeoy-kkk/p/17538473.html

相关文章

  • CSP - J 训练营
    Day1数据结构含义:拿来存储数据的结构常见形式:1.变量只能存一个数。2.数组所有数组都开在全局变量。堆空间全局变量在堆空间。空间为$256M$,可以存$6.4×10^7$个int。栈空间局部变量在栈空间。空间为$64KB$,只能存$1.6×10^5$个int。......
  • 暑期记录2
    7月3这周我就开始了java的学习,首先我根据老师的要求下载并安装了编程软件eclipse,但是下载安装完成之后还需要下载jdk,修改环境配置,我通过查阅资料,大约花了1个小时才终于算是彻底完成了java编程的前期工作,面对一个全新的编程软件,开始是比较迷茫的,但通过上网查阅相关资料,对软件以及j......
  • 暑期第三周总结
    本周花在学习上的时间大概为21小时,花在代码上的时间大概为11小时。花在解决问题上的时间大概为4小时。本周,我完成了hive数据库的使用,包括但不限于创建数据库,删除数据库,数据库和hdfs的关系,创建表的语法,数据类型,内部表,外部表,内部表和外部表的区别,比如创建内部表的语法为createtable......
  • 行行AI人才直播第8期:新加坡国立大学在读博士生张傲《多模态大语言模型(MLLM)的简介及
    随着ChatGPT在各领域展现出非凡能力,多模态大型语言模型(MLLM)近来也成为了研究的热点,它利用强大的大型语言模型(LLM)作为“大脑”,可以执行各种多模态任务。更让人感慨的是,MLLM展现出了传统方法所不具备的能力,比如能够根据图像创作故事,无需OCR的数学推理等,这为实现人工智能的通用......
  • 暑期熔炉7月7
    你用尾巴,摇来一个家,所以我一生都称呼你爸爸,我的尾巴小,可它在长大,骄傲真可怕。    今日酒醒无梦,梦回唐朝,我好似见到那李白。梦里的他也在喝酒,还在欣赏一副洛神图。洛神图中有诗提,是那陈王曹植所作。洛神舞美陈王才,太白醉入我梦来。......
  • 20230706巴蜀暑期集训测试总结
    T1我是个大聪明!一眼矩乘。构造转移矩阵构造了3.5h!最开始以为只有\(15\times15\),直接手打。写到一半发现不一定四种颜色都有,是\(52\times52\)的,这时候狗被脑子吃了,还想手打,于是就打到了3h。差不多打了一大半,脑子终于把狗还回来了,意识到就算打完也不可能调得出来,就开始另辟蹊径,......
  • 20230707巴蜀暑期集训测试总结
    T1SPFA就能过!给我震惊到了。可以斜率优化。对每个站点维护一个凸包。\[f(x)=Ax^2+Bx+C\\dp_{v,q}=\min_{i=0}^{p}\{dp_{u,i}+f(p-i)\}\\(i,dp_{x,i}+Ai^2-Bi)\]T2考场想了想区间dp,有点思路但是时间不多了有点慌,打个暴搜直接跑。相当于将位置当作第二关键字比较,最大的数......
  • CDMP国际数据治理认证训练营来了(7-8月)
    大家好,我是独孤风,一位曾经的港口煤炭工人,目前在某国企任大数据负责人,公众号大数据流动主理人。在最近的两年的时间里,因为公司的需求,还有大数据的发展趋势所在,我开始学习数据治理的相关知识。经过一段时间的努力,我也终于通过了CDMP国际数据治理认证考试。离我研究生开学还有两个......
  • yolov5的训练策略
    yolov5——训练策略前言1.训练预热——Warmup1.1what是Warmup1.2why用Warmup1.3常见Warmup类型1.4yolov5中的Warmup2.自动调整锚定框——Autoanchor2.1what是anchor2.2why用anchor2.1yolov5默认锚定框2.2yolov5自动锚框3.超参数进化——遗传......
  • 浙大暑期密码学课程-笔记|两方安全计算
    浙大暑期密码学课程-笔记|两方安全计算视频地址:浙大暑期Crypto课程-MPCI(上)、浙大暑期Crypto课程-MPCI(下)参考:笔记分享|浙大暑期密码学课程:两方安全计算摘要多方安全计算(MPC)有着广泛的应用,本次课程将由来自浙江大学的张秉晟老师带来,主要讲解两方安全协议。安全多方计算的定......