首页 > 其他分享 >8.12信息学集训_摸底

8.12信息学集训_摸底

时间:2024-08-12 08:56:36浏览次数:10  
标签:信息学 le 10 int ll long 8.12 数据 摸底

目录

P9955 [USACO20DEC] Do You Know Your ABCs? B

有三个正整数 \(A\)、\(B\) 和 \(C\)(\(A\le B\le C\))。这些数字范围在 \(1\ldots 10^9\) 之间的整数(不一定各不相同),并且是 \(A\)、\(B\)、\(C\)、\(A+B\)、\(B+C\)、\(C+A\) 和 \(A+B+C\) 的某种排列。

给定这七个整数,求出 \(A\)、\(B\) 和 \(C\)。可以证明,答案是唯一的。

输入格式:输入一行,包含七个空格分隔的整数。
输出格式:输出 \(A\)、\(B\) 和 \(C\),用空格分隔。

in:
2 2 11 4 9 7 9
out:
2 2 7

【分析】7个数字中选3个数,匹配要求,推导一下有如下信息

\[\begin{align*} &A\le B \le C \\ &A \le B\le C, A+B \le C+ A \le B+C \le A+B+C\\ &C = A+B+C - A-B \quad \text{(^_^)} \end{align*} \]

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1E9 + 7;

int main(int argc, char* argv[]) {
    int a[10], n = 7;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    sort(a + 1, a + 1 + n);
    a[3] = a[7] - a[1] - a[2];
    cout << a[1] << " " << a[2] << " " << a[3];
    return 0;
}

P5436 【XR-2】缘分

一禅和师父约定一个正整数 \(n\),接着他们各自在心里想一个不超过 \(n\) 的正整数,这两个数的最小公倍数最大会是多少。

输入格式:
多组数据,第一行一个正整数 \(T\),表示数据组数。
接下来的 \(T\) 行,每行一个正整数 \(n\),表示一禅和师父约定的正整数。

输出格式:对每组数据,一行一个正整数,表示答案。

in:
1
3
out:
6

【样例说明】不超过 \(3\) 的两个正整数的最小公倍数的最大值为 \(\mathrm{lcm}(2,3) = 6\)。

【数据规模与约定】

对 \(50\%\) 的数据,\(1 \le T,n \le 100\)。

对 \(100\%\) 的数据,\(1 \le T \le 100, 1 \le n \le 10^9\)。

【分析】\(a,b\le n,\quad ans = max(lcm(a,b))\)

方法1:枚举 \(a,b\),复杂度 \(O(Tn^2)\),得分 50;

方法2:推导一下,\(lcm(a,b) = a*b/gcd(a,b)\),想 \(lcm\) 越大,那么 \(a*b\) 越大,\(gcd(a,b)\) 越小
\(gcd(n-1, n)=1\),所以 \(a=n-1, b=n\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
typedef long long ll;
ll gcd(ll a, ll b) {
    return b ? gcd(b, a % b) : a;
}
ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}
// 求 max(lcm(a,b)) = max(a*b/gcd(a,b)),则a b互质就是答案
int main() {
    ll t, n;
    cin >> t;
    while (t--) {
        cin >> n;
        cout << (n == 1 ? 1 : n * (n - 1)) << endl;
    }
    return 0;
}

P1182 数列分段 Section II

对于给定的一个长度为 \(N\) 的正整数数列 \(A_{1\sim N}\),现要将其分成 \(M\)(\(M\leq N\))段,并要求每段连续,且每段和的最大值最小。

in:
5 3
4 2 4 5 1
out:
6

【数据规模与约定】

对于 \(20\%\) 的数据,\(N\leq 10\)。
对于 \(40\%\) 的数据,\(N\leq 1000\)。
对于 \(100\%\) 的数据,\(1\leq N\leq 10^5\),\(M\leq N\),\(A_i < 10^8\), 答案不超过 \(10^9\)。

【分析】最大值最小,典型二分答案

二分左边界 x, chk 当最大值 x 的时候是否合法
思考 是否需要 long long

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, m, a[N];
// 最大值 x 的情况下能否分出至多 m 段
bool chk(int x) {
    int s = 0, t = 0;
    for (int i = 1; i <= n; i++) {
        if (t + a[i] < x) t += a[i];
        else if (t + a[i] == x) t = 0, s++;
        else t = a[i], s++;
    }
    if (t) s++;
    return s <= m;
}
int main() {
    int l = 1, r = 1e9, ans = r;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i], l = max(l, a[i]);
    while (l <= r) {
        int mid = l + r >> 1;
        chk(mid) ? r = mid - 1, ans = mid : l = mid + 1;
    }
    cout << ans << endl;
    return 0;
}

P1032 [NOIP2002 提高组] 字串变换

已知有两个字串 \(A,B\) 及一组字串变换的规则(至多 \(6\) 个规则),形如:

  • \(A_1\to B_1\)。
  • \(A_2\to B_2\)。

规则的含义为:在 \(A\) 中的子串 \(A_1\) 可以变换为 $ B_1\(,\)A_2$ 可以变换为 \(B_2\cdots\)。

输入格式:第一行有两个字符串 \(A,B\)。接下来若干行,每行有两个字符串 \(A_i,B_i\),表示一条变换规则。

输出格式:若在 \(10\) 步(包含 \(10\) 步)以内能将 \(A\) 变换为 \(B\),则输出最少的变换步数;否则输出 NO ANSWER!

in:
abcd xyz
abc xu
ud y
y yz
out:
3

【数据规模与约定】
对于 \(100\%\) 数据,保证所有字符串长度的上限为 \(20\)。

【分析】最小步数,一眼bfs

题目主要在数据的处理上面有点难度,现在 x,y 是字符串类型,不好记录 g[x][y]=1 的情况。

思考一下,可以使用 map<pair<string,string>, bool> mp;

问题解决, bfs 即可。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
string A, B, a, b;
map<pair<string, string>, bool> mp;
map<string, int> st;

void bfs() {
    queue<string> q;
    q.push(A), st[A] = 1;
    while (q.size()) {
        auto u = q.front(); q.pop();
        if (st[u] > 10) continue;
        if (u == B) {
            cout << st[u] - 1 << endl;
            return;
        }
        for (auto it : mp) {
            a = it.first.first, b = it.first.second;
            int p = u.find(a);
            while (p != -1) {
                string v = u;
                v.replace(v.begin() + p, v.begin() + p + a.size(), b);
                if (!st[v]) st[v] = st[u] + 1, q.push(v);
                p = u.find(a, p + a.size());
            }
        }
    }
    cout << "NO ANSWER!" << endl;
}
int main() {
    cin >> A >> B;
    while (cin >> a >> b) mp.insert({make_pair(a, b), 1});
    bfs();
    return 0;
}

P1020 [NOIP1999 提高组] 导弹拦截

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式:一行,若干个整数,中间由空格隔开。

输出格式:两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

in:
389 207 155 300 299 170 158 65
out:
6
2

【数据规模与约定】
对于前 \(50\%\) 数据(NOIP 原题数据),满足导弹的个数不超过 \(10^4\) 个。该部分数据总分共 \(100\) 分。可使用\(\mathcal O(n^2)\) 做法通过。
对于后 \(50\%\) 的数据,满足导弹的个数不超过 \(10^5\) 个。该部分数据总分也为 \(100\) 分。请使用 \(\mathcal O(n\log n)\) 做法通过。

对于全部数据,满足导弹的高度为正整数,且不超过 \(5\times 10^4\)。

【分析】题目含有两个问题

// v1 : 最长不上升子序列长度
// v2 : 需要多少导弹

解法1:DP,复杂度 \(O(n^2)\)

解法2:贪心+二分,复杂度 \(O(nlogn)\)

具体内容不在赘述,可查阅

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int n = 0, a[N], f[N], h[N];
// v1 : 最长下降子序列长度
// v2 : 需要多少导弹
namespace dp {
void solve() {
    int ans1 = 0, ans2 = 0;
    for (int i = 1; i <= n; i++) {
        f[i] = 1;
        for (int j = 1; j < i; j++)
            if (a[i] <= a[j]) f[i] = max(f[i], f[j] + 1);
        ans1 = max(ans1, f[i]);
    }
    for (int i = 1; i <= n; i++) {
        int k = 0;
        while (k <= ans2 && h[k] < a[i]) k++;
        h[k] = a[i];
        if (k > ans2) ans2++;
    }
    cout << ans1 << endl << ans2 << endl;
}

};  // namespace dp
namespace binary_Search {
void solve() {
    int ans1 = 0, ans2 = 0;
    for (int i = n; i >= 1; i--) {
        if (i == n || f[ans1 - 1] <= a[i]) f[ans1++] = a[i];
        else *upper_bound(f, f + ans1, a[i]) = a[i];
    }
    for (int i = 1; i <= n; i++) {
        int k = lower_bound(h + 1, h + 1 + ans2, a[i]) - h;
        h[k] = a[i];
        if (k > ans2) ans2++;
    }
    cout << ans1 << endl << ans2 << endl;
}
};  // namespace binary_Search
int main() {
    while (cin >> a[++n]); n--;
    // dp::solve();
    binary_Search::solve();
    return 0;
}

P1077 [NOIP2012 普及组] 摆花

小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 \(m\) 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 \(n\) 种花,从 \(1\) 到 \(n\) 标号。为了在门口展出更多种花,规定第 \(i\) 种花不能超过 \(a_i\) 盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。

试编程计算,一共有多少种不同的摆花方案。

输入格式:第一行包含两个正整数 \(n\) 和 \(m\),中间用一个空格隔开。第二行有 \(n\) 个整数,每两个整数之间用一个空格隔开,依次表示 \(a_1,a_2, \cdots ,a_n\)。

输出格式:一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对 \(10^6+7\) 取模的结果。

in:
2 4
3 2
out:
2

【数据范围】

对于 \(20\%\) 数据,有 \(0<n \le 8,0<m \le 8,0 \le a_i \le 8\)。

对于 \(50\%\) 数据,有 \(0<n \le 20,0<m \le 20,0 \le a_i \le 20\)。

对于 \(100\%\) 数据,有 \(0<n \le 100,0<m \le 100,0 \le a_i \le 100\)。

【分析】

好好阅读理解这句话的含义:摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。

也就意味着,不需要考虑花的位置,只需要考虑数量

那么问题就很显然,这是一个多重背包的裸题。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n, m, a[N], mod = 1e6 + 7;

namespace DP1 {
int dp[N][N];  // dp[i][j] 用前 i 种花摆 j 盆的方案数
void solve() {
    for (int i = 0; i <= n; i++)
        dp[i][0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            for (int k = 0; k <= a[i] && k <= j; k++) {
                int& t = dp[i][j];
                t = (t + dp[i - 1][j - k]) % mod;
            }
    cout << dp[n][m] << endl;
}
};  // namespace DP1

namespace DP2 {
int dp[N];  // dp[j] 摆 j 盆的方案数
void solve() {
    dp[0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = m; j >= 1; j--)
            for (int k = 1; k <= a[i] && k <= j; k++) {
                int& t = dp[j];
                t = (t + dp[j - k]) % mod;
            }
    cout << dp[m] << endl;
}
};  // namespace DP2

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    DP1::solve();
    DP2::solve();
    return 0;
}

T264125 黑暗能量

有\(n\) 瓶装有黑暗能量的容器,第 \(i\) 个容器里装有质量为 \(a_i\) 的黑暗能量。
两人尽可能多的平分黑暗能量,剩下无法平分的黑暗能量只能放弃使用。

【数据规模与约定】

本题共有 \(20\) 个测试点。

对于 \(50\%\) 的数据,\(n \le 13\);

对于 \(70\%\) 的数据,\(n \le 50\),提供的黑暗能量的总质量不超过 \(10^3\);

对于 \(100\%\) 的数据,\(n \le 500\),提供的黑暗能量的总质量不超过 \(10^5\)。

注意:对于以上三档数据,每档数据中分别含有 \(1\) 个测试点空间限制为 \(2\) MB,即总共有 \(15\%\) 的测试点空间限制为 \(2\) MB,其余测试点空间限制为 \(256\) MB。

【分析】

对于 \(50\%\) 的数据,\(n \le 13\);--- 枚举所有情况 \(3^{13}\),很小

满分解法,DP + 滚动数组优化,具体描述看代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 501, INF = 0x3f3f3f3f;
int n, m, a[N];

// 枚举 TLE:3^n ---- 012
void solve1() {
    int ans = 0, tt = pow(3, n);
    for (int i = 0; i < tt; i++) {
        int t = i, p = n, b[3] = {0};
        while (t) {
            b[t % 3] += a[p--], t /= 3;
        }
        if (b[1] == b[2])
            ans = max(ans, b[1]);
    }
    cout << 2 * ans << endl;
}

// dp[i][j][k] -- 前 i件物品,羊j 狼k 的情况是否存在
void solve2() {
    bool dp[501][501][501];
    memset(dp, 0x00, sizeof dp);
    dp[0][0][0] = 1;
    int p = 500;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= p; j++) {
            for (int k = 0; k <= p; k++) {
                bool& t = dp[i][j][k];
                t = dp[i - 1][j][k];
                if (!t && j >= a[i])
                    t = dp[i - 1][j - a[i]][k];
                if (!t && k >= a[i])
                    t = dp[i - 1][j][k - a[i]];
            }
        }
    }
    int ans = 0;
    for (int i = 0; i <= p; i++)
        ans = max(ans, dp[n][i][i] ? i : 0);
    cout << 2 * ans << endl;
}

// dp[i][j] -- 前 i件物品,羊狼差距 j 的最大质量
void solve3() {
    int dp[501][50001];
    memset(dp, 0x80, sizeof dp);
    dp[0][0] = 0;
    int p = 50000;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= p; j++) {
            int& t = dp[i][j];
            t = dp[i - 1][j];
            if (j + a[i] <= p)
                t = max(t, dp[i - 1][j + a[i]] + a[i]);
            t = max(t, dp[i - 1][abs(j - a[i])] + a[i]);
        }
    }
    cout << dp[n][0] << endl;
}

// dp[i][j] -- 前 i件物品,羊狼差距 j 的最大质量
void solve4() {
    int dp[2][100001];
    memset(dp, 0x80, sizeof dp);
    dp[0][0] = 0;
    int p = 50000;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= p; j++) {
            int& t = dp[i & 1][j];
            t = dp[(i - 1) & 1][j];
            if (j + a[i] <= p)
                t = max(t, dp[(i - 1) & 1][j + a[i]] + a[i]);
            t = max(t, dp[(i - 1) & 1][abs(j - a[i])] + a[i]);
        }
    }
    cout << dp[n & 1][0] << endl;
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i], m += a[i];

    solve1();
    solve2();
    solve3();
    solve4();

    return 0;
}

标签:信息学,le,10,int,ll,long,8.12,数据,摸底
From: https://www.cnblogs.com/hellohebin/p/18352227

相关文章

  • 2021年庐阳区青少年信息学科普日真题- 跳跃(jump)
    题目描述猴子的正上方,每1米处,都有一个桃子,一共有N个桃子,每个桃子都有其能量值,摘下这个桃子吃下就获得了这个能力值。猴子每跳1米会消耗1个点能量,在能量值允许的下,它可以跳到任何一个可以到达的高度,并且将这个高度及以下高度的桃子摘下吃掉。确保猴子初始的能量一定可以摘下......
  • 信息学奥赛一本通 1128 图像模糊处理
    1128:图像模糊处理时间限制:1000ms      内存限制:65536KB提交数:69990   通过数: 30350【题目描述】给定n行m列的图像各像素点的灰度值,要求用如下方法对其进行模糊化处理:1.四周最外侧的像素点灰度值不变;2.中间各像素点新灰度值为该像素点及其上下左......
  • 《信息学奥赛一本通编程启蒙》3031-3050(Scratch、C、C++、python)
    3031:练7.3买图书(C、C++、python)3031:练7.3买图书(C、C++、python)-CSDN博客3032:练7.4梯形面积(C、C++、python)3032:练7.4梯形面积(C、C++、python)-CSDN博客3033:【例8.1】人民币支付(Scratch、C、C++、python)3033:【例8.1】人民币支付(Scratch、C、C++、python)-CSDN博客3......
  • 函数(下):数学信息学不分家
    在上一章,我们已经初步了解了关于函数的一些知识。另外提一嘴,函数有多个参数时,一般使用逗号分隔开,不管是定义函数还是调用函数。那么,接下来,我们继续学习函数。首先先说一点,上期的代码太乱了,本期决定减少出现的编程语言,只出现根据tiobe语言排行榜当下最流行的四门编程语言:python,C......
  • 全面弄懂少儿编程与信息学奥赛-V1.0版
    全面弄懂少儿编程与信息学奥赛-V1.0版本次讲述话题都为作者自己学编程以及所在专业,行业,以及教学经验和实践来原创撰写,不保证100%正确,但是保证99%的相对正确,同样,我希望任何人去看待任何问题都理性思考,独立思考,自己去评判别人说的是否有道理,这个世界上任何事都没有绝对的对与错,但......
  • 【信息学奥赛提高组】组合数学和线性代数初步
    组合数学和线性代数目录组合数学和线性代数组合数学组合数TwelvefoldWay基础计数隔板法整数划分第二类斯特林数容斥原理反演二项式反演莫比乌斯反演高维前缀和鸽巢原理线性代数向量和矩阵向量矩阵高斯消元线性基组合数学组合数\(\binom{m}{n}\)表示\(m\)个物品选出\(n\)个的......
  • 【信息学奥赛提高组】简单、初等数论
    初等数论目录初等数论整除与约数带余除法和整除质数与约数算数基本定理公约数和公倍数更相减损术欧几里得算法(辗转相除法)裴蜀定理拓展欧几里得算法(Ex-GCD)同余同余方程逆元预处理逆元威尔逊定理完全剩余系费马小定理Miller-Rabin测试简化剩余系欧拉定理扩展欧拉定理欧拉函数中国剩......
  • C++queue,deque浅显了解及运用(信息学竞赛专用)
    当然也可以不看==> 阅读我的文章前请务必先阅读此文章! 都是废话目录阅读文章须知引言队列(queue)队列简介​编辑队列的创建队列的操作手写队列双端队列(deque)双端队列简介双端队列的创建双端队列的操作 手写双端队列(原理)写在最后阅读文章须知为了得到......
  • C++题解(7) 信息学奥赛一本通:1055:判断闰年
    【题目描述】判断某年是否是闰年。如果公元a年是闰年输出Y,否则输出N。【输入】输入只有一行,包含一个整数a(0<a<3000)。【输出】一行,如果公元a年是闰年输出Y,否则输出N。【输入样例】2006【输出样例】N【知识链接:如何判断闰年】(1)能被4整除,但不......
  • C++题解(6) 信息学奥赛一本通:2069:【例2.12 】糖果游戏
    【题目描述】某幼儿园里,有5个小朋友编号为1、2、3、4、5,他们按自己的编号顺序围坐在一张圆桌旁。他们身上都有若干个糖果(键盘输入),现在他们做一个分糖果游戏。从1号小朋友开始,将自己的糖果均分三份(如果有多余的糖果,则立即吃掉),自己留一份,其余两份分给他的相邻的两个小朋友。......