当前位置: 代码迷 >> 综合 >> NOIP 2018 提高组 真题
  详细解决方案

NOIP 2018 提高组 真题

热度:5   发布时间:2023-12-16 11:12:51.0

在这里插入图片描述

D1T1铺设道路

时间限制: 1 s 1s 1s
空间限制: 512 M B 512MB 512MB

题目描述

春春是一名道路工程师,负责铺设一条长度为 n 的道路。
铺设道路的主要工作是填平下陷的地表。整段道路可以看作是 n n n 块首尾相连的区域,一开始,第 i i i 块区域下陷的深度为 d i di di
春春每天可以选择一段连续区间 [ L , R ] [L,R] [L,R],填充这段区间中的每块区域,让其下陷深度减少 1 1 1
在选择区间时,需要保证,区间内的每块区域在填充前下陷深度均不为 0 0 0
春春希望你能帮他设计一种方案,可以在最短的时间内将整段道路的下陷深度都变为 0 0 0

输入格式

输入文件包含两行,第一行包含一个整数 n n n,表示道路的长度
第二行包含 n n n 个整数,相邻两数间用一个空格隔开,第 i i i 个整数为 d i di di

输出格式

输出文件仅包含一个整数,即最少需要多少天才能完成任务。

样例数据
input
6   
4 3 2 5 3 5
output
9
样例说明

一种可行的最佳方案是,依次选择: [ 1 , 6 ] 、 [ 1 , 6 ] 、 [ 1 , 2 ] 、 [ 1 , 1 ] 、 [ 4 , 6 ] 、 [ 4 , 4 ] 、 [ 4 , 4 ] 、 [ 6 , 6 ] 、 [ 6 , 6 ] [1,6]、[1,6]、[1,2]、[1,1]、[4,6]、[4,4]、[4,4]、[6,6]、[6,6] [1,6][1,6][1,2][1,1][4,6][4,4][4,4][6,6][6,6]

数据规模与约定

对于 30 30 30% 的数据, 1 ≤ n ≤ 10 1 ≤ n ≤ 10 1n10
对于 70 70 70% 的数据, 1 ≤ n ≤ 1000 1 ≤ n ≤ 1000 1n1000
对于 100 100 100% 的数据, 1 ≤ n ≤ 100000 , 0 ≤ d i ≤ 100001 ≤ n ≤ 100000 , 0 ≤ d i ≤ 10000 1≤n≤100000,0≤di≤100001≤n≤100000,0≤di≤10000 1n100000,0di100001n100000,0di10000在这里插入图片描述
单调队列维护即可
在这里插入图片描述

#include<bits/stdc++.h>
#define ll long long
using namespace std;int n, ans, tot;
int a[100010], q[100010];inline void init() {
    scanf("%d", &n);for(int i = 1; i <= n; i++)scanf("%d", &a[i]);
}inline void work() {
    q[++tot] = a[1];for(int i = 2; i <= n; i++){
    if(a[i] <= q[tot] && tot) ans += q[tot--]-a[i];while(a[i] <= q[tot] && tot) tot--;q[++tot] = a[i];}
}inline void outo() {
    printf("%d", ans+q[tot]);
}
int main() {
    init();work();outo();return 0;
}

在这里插入图片描述
在这里插入图片描述

D1T2货币系统

时间限制: 1 s 1s 1s
空间限制: 512 M B 512MB 512MB

题目描述

在网友的国度中共有 n n n 种不同面额的货币,第 i i i 种货币的面额为 a [ i ] a[i] a[i],你可以假设每一种货币都有无穷多张。为了方便,我们把货币种数为 n n n、面额数组为 a [ 1.. n ] a[1..n] a[1..n] 的货币系统记作 ( n , a ) (n,a) (n,a)
在一个完善的货币系统中,每一个非负整数的金额 x x x 都应该可以被表示出,即对每一个非负整数 x x x,都存在 n 个非负整数 t [ i ] t[i] t[i] 满足 a [ i ] × t [ i ] a[i]×t[i] a[i]×t[i] 的和为 x x x。然而, 在网友的国度中,货币系统可能是不完善的,即可能存在金额 x x x 不能被该货币系统表示出。例如在货币系统 n = 3 , a = [ 2 , 5 , 9 ] n=3, a=[2,5,9] n=3,a=[2,5,9]中,金额 1 , 3 1,3 1,3 就无法被表示出来。
两个货币系统 ( n , a ) (n,a) (n,a) ( m , b ) (m,b) (m,b) 是等价的,当且仅当对于任意非负整数 x x x,它要么均可以被两个货币系统表出,要么不能被其中任何一个表出。
现在网友们打算简化一下货币系统。他们希望找到一个货币系统 ( m , b ) (m,b) (m,b),满足 ( m , b ) (m,b) (m,b) 与原来的货币系统 ( n , a ) (n,a) (n,a) 等价,且 m m m尽可能的小。他们希望你来协助完成这个艰巨的任务:找到最小的 m m m

输入格式

输入文件的第一行包含一个整数 T T T,表示数据的组数。
接下来按照如下格式分别给出 T T T 组数据。 每组数据的第一行包含一个正整数 n n n
接下来一行包含 n n n 个由空格隔开的正整数 a [ i ] a[i] a[i]

输出格式

输出文件共有 T T T 行,对于每组数据,输出一行一个正整数,表示所有与 ( n , a ) (n,a) (n,a)等价的货币系统 ( m , b ) (m,b) (m,b) 中,最小的 m m m

样例数据
input
2 
4 
3 19 10 6 
5 
11 29 13 19 17
output
2
5
样例说明

在第一组数据中,货币系统 ( 2 , [ 3 , 10 ] ) (2, [3,10]) (2,[3,10]) 和给出的货币系统 ( n , a ) (n, a) (n,a) 等价,并可以验证不存在 m < 2 m < 2 m2 的等价的货币系统,因此答案为 2 2 2。 在第二组数据中,可以验证不存在 m < n m < n mn的等价的货币系统,因此答案为 5 5 5

数据规模与约定

在这里插入图片描述
对于 100 100 100% 的数据,满足 1 ≤ T ≤ 20 , n , a [ i ] ≥ 1 1 ≤ T ≤ 20, n,a[i] ≥ 1 1T20,n,a[i]1
在这里插入图片描述
由题意可推,b必为a的子集
因为要使b中的元素最少,我们可以想象成b先复制一份a数组,然后再去掉一些并非必要的数即可
什么是并非必要的数呢?如果a集合中的某一个数可以由a集合中另外的数组成,这个数就不是必要的数
在这里插入图片描述

#include<bits/stdc++.h>
#define ll long long
using namespace std;int n, a[105], f[25005], ans, T;inline void init() {
    scanf("%d", &n);memset(f, 0, sizeof f);for(int i = 1; i <= n; i++) {
    scanf("%d", &a[i]);f[a[i]] = 2;//2表示a集合原先存在的数}sort(a+1, a+1+n);
}inline void work() {
    ans = 0;for(int i = 1; i <= a[n]; i++) for(int j = 1; j <= n && f[i]; j++)if(i+a[j] <= a[n]) f[a[j]+i] = 1;//1表示可以拼凑出来的数for(int i = 1; i <= n; i++)if(f[a[i]] == 2) ans++;//原a集合中有多少个数不能被拼凑,就是必要的数
}inline void outo() {
    printf("%d\n", ans);
}
int main() {
    scanf("%d", &T);while(T--) {
    init();work();outo();}return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
#define ll long long
using namespace std;const int N = 5e3+10;
int n, m, len, dep, xx, yy;
int lin[N], ans[N], res[N];
bool vis[N];
vector<int> vec[N];
struct psx{
    int next, x, y;}e[N<<1];inline void insert(int x, int y) {
    e[++len].next = lin[x];e[len].x = x;e[len].y = y;lin[x] = len;
}inline void init() {
    scanf("%d%d", &n, &m);for(int i = 1, v, u; i <= m; i++) {
    scanf("%d%d", &u, &v);insert(u, v);insert(v, u);vec[v].push_back(u);vec[u].push_back(v);}for(int i = 1; i <= n; i++)sort(vec[i].begin(), vec[i].end());
}inline void dfs1(int x, int fa) {
    if(vis[x]) return;vis[x] = 1;ans[++dep] = x;for(int i = 0; i < vec[x].size(); i++) {
    int y = vec[x][i];if(y == fa) continue;dfs1(y, x);}
}inline void dfs2(int x, int fa) {
    if(vis[x]) return; vis[x] = 1;res[++dep] = x;for(int i = 0; i < vec[x].size(); i++) {
    int y = vec[x][i];if(y == fa) continue;if((y==xx && x==yy) || (y==yy && x==xx)) continue;dfs2(y, x);}
}inline bool check() {
    for(int i = 1; i <= n; i++) {
    if(res[i] < ans[i]) return 1;if(res[i] > ans[i]) return 0;}
}inline void change() {
    for(int i = 1; i <= n; i++)ans[i] = res[i];
}inline void work() {
    if(m == n-1) {
    dep = 0;dfs1(1, 0);return;}//如果是一棵树for(int i = 1; i <= len; i += 2) {
    dep = 0;xx = e[i].x;yy = e[i].y;//记录删去边的信息memset(vis, 0, sizeof vis);dfs2(1, 0);if(dep < n) continue;if(!ans[1]) change();else if(check()) change();//更新答案}//基环树,每次枚举删去其中一条边,选择字典序最小的方案
}inline void outo() {
    for(int i = 1; i <= n; i++)printf("%d ", ans[i]);
}
int main() {
    init();work();outo();return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

65分部分分
#include<bits/stdc++.h>
#define ll long long
using namespace std;const int mod = 1e9+7;
int n, m;
inline void init() {
    scanf("%d%d",&n,&m);
}
inline int P(int a,int b) {
    int c = 1;while(b){
    if(b&1) c = 1LL*c*a%mod;a = 1LL*a*a%mod;b >>= 1;} return c;
}
inline void work() {
    if(n == 2) {
    printf("%d\n",4LL*P(3,m-1)%mod);return;};if(n == 3)  {
    if(m == 1) puts("8");else if (m == 2) puts("36");else if (m == 3) puts("112");else printf("%d\n",112LL*P(3,m-3)%mod);return;}
}int main() {
    init();work();return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  相关解决方案