BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛(10)题解

Bob和Alice(1)

思路
模 拟 即 可 模拟即可
时间复杂度 O 1 O1 O1

#include <bits/stdc++.h>
#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define der(i,a,b) for(int i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;

signed main()
{
    string s , t ;
    cin >> s >> t ;
    int res = 0 ;
    fer(i,0,sz(s)-1)
    {
        if(s[i] == t[i])
            res ++ ;
    }
    cout << res ;
    
    return 0;
}

Bob和Alice(2)

思路
模 拟 即 可 模拟即可
时间复杂度 O n On On

#include <bits/stdc++.h>
#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define der(i,a,b) for(int i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;

int n ;
int a[N] , b[N] , c[N] ;

signed main()
{
    cin >> n ;
    fer(i,1,n) sf(a[i]) ;
    fer(i,1,n) sf(b[i]) ;
    fer(i,1,n-1) sf(c[i]) ;
    
    int res = 0 ;
    a[0] = -2 ;
    
    fer(i,1,n)
    {
        res += b[a[i]] ;
        if(a[i] == a[i-1] + 1)
            res += c[a[i-1]] ;
    }
    cout << res ;
    
}

Bob和Alice(3)

思路
对 每 一 个 i [ 1 < = i < = n − 1 ] 对每一个i [1 <= i <= n - 1] i[1<=i<=n1]
B i > = m a x ( A i , A i + 1 ) B_i>=max(A_i,A_{i+1}) Bi>=max(Ai,Ai+1)

因 此 因此
B 1 > = m a x ( A 1 , A 2 ) B_1>=max(A_1,A_2) B1>=max(A1,A2)
B 2 > = m a x ( A 2 , A 3 ) B_2>=max(A_2,A_3) B2>=max(A2,A3)

B n − 1 > = m a x ( A n − 1 , A n ) B_{n-1}>=max(A_{n-1},A_{n}) Bn1>=max(An1,An)

所 以 可 以 得 到 所以可以得到
A 1 < = B 1 A_1<=B_1 A1<=B1
A 2 < = m i n ( B 1 , B 2 ) A_2<=min(B_1,B_2) A2<=min(B1,B2)
A 3 < = m i n ( B 2 , B 3 ) A_3<=min(B_2,B_3) A3<=min(B2,B3)

A n − 1 < = m i n ( B n − 2 , B n − 1 ) A_{n-1}<=min(B_{n-2},B_{n-1}) An1<=min(Bn2,Bn1)
A n < = B n − 1 A_n<=B_{n-1} An<=Bn1

因 此 因此
A 1 < = B 1 A_1<=B_1 A1<=B1
A i < = m i n ( B i , B i − 1 ) [ 2 < = i < = n − 1 ] A_{i}<=min(B_i,B_{i-1})[2 <= i <= n - 1] Ai<=min(Bi,Bi1)[2<=i<=n1]
A n < = B n − 1 A_n<=B_{n-1} An<=Bn1

所 以 答 案 为 所以答案为
B 1 + B n − 1 + ∑ i = 2 n − 1 m i n ( B i , B i − 1 ) B_1+B_{n-1}+\sum_{i=2}^{n-1}min(B_i,B_{i-1}) B1+Bn1+i=2n1min(Bi,Bi1)
时间复杂度 O n On On

#include <bits/stdc++.h>
#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define der(i,a,b) for(int i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;

int n ;
int a[N] ;
int b[N] ;


signed main()
{  
    cin >> n ;
    fer(i,1,n-1) sf(b[i]) ;
    
    int s = b[1] ;
    fer(i,2,n-1)
        s += min(b[i] , b[i-1]) ;
    s += b[n-1] ;
    
    cout << s ;
}

Bob和Alice(4)

思路
先 暴 力 求 出 前 10 项 先暴力求出前10项 10
在这里插入图片描述
我 们 可 以 发 现 我们可以发现
0 = 0 0 = 0 0=0
1 = 0 + 1 1 = 0 + 1 1=0+1
3 = 0 + 1 + 2 3 = 0 + 1 + 2 3=0+1+2
6 = 0 + 1 + 2 + 3 6 = 0 + 1 + 2 + 3 6=0+1+2+3
因 此 因此
答 案 为 0 + 1 + 2 + . . . . . + n = n ∗ ( n − 1 ) 2 答案为0 + 1 + 2 + ..... +n=\frac{n*(n-1)}{2} 0+1+2+.....+n=2n(n1)
暴力找规律代码

#include <bits/stdc++.h>
#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define der(i,a,b) for(int i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
inline void de(int x) {cout << x << "\n" ;}
inline void de2(int a , int b) {cout << a << " " << b << "\n" ;}
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;

signed main()
{
    fer(n,1,10)
    {
        vector<int> v ;
        fer(i,1,n) v.pb(i) ;
        sort(all(v)) ;
        
        int res = 0 ;
        do{
            int s = 0 ;
            int k = 0 ;
            for(auto i : v)
            {
                k ++ ;
                s += k % i ;
            }
            res = max(res , s) ;
        }while(next_permutation(all(v))) ;
        
        de2(n,res) ;
    }
}

A C 代 码 AC代码 AC
时间复杂度 O 1 O1 O1

#include<bits/stdc++.h>
using namespace std;

signed main()
{
    long long n ;
    cin >> n ;
    
    cout << n * (n - 1) / 2 ;
}

Bob和Alice(5)

思路
这 题 是 这 6 道 当 中 最 难 的 一 道 了 这题是这6道当中最难的一道了 6
难 点 在 于 首 先 要 想 到 枚 举 答 案 难点在于首先要想到枚举答案
其 次 是 边 界 问 题 其次是边界问题

首 先 考 虑 暴 力 O n 2 必 定 超 时 首先考虑暴力On^2必定超时 On2
考 虑 如 何 优 化 考虑如何优化
我 们 发 现 答 案 一 定 是 从 1 到 n 我们发现答案一定是从1到n 1n
对 每 一 个 答 案 x , 我 们 如 果 可 以 用 l o g n 的 时 间 求 出 有 多 少 个 区 间 的 第 二 大 值 等 于 x 对每一个答案x,我们如果可以用logn的时间求出有多少个区间的第二大值等于x x,lognx
此 题 即 迎 刃 而 解 此题即迎刃而解

假 设 答 案 为 x 假设答案为x x
它 的 下 标 为 i d 它的下标为id id

![在这里插入图片描述](https://img-blog.csdnimg.cn/8ad98b7bdc54491aac59b5aa4563309d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAeXVlc2hlaGFuamlhbmc=,size_20,color_FFFFFF,t_70,g_se,x_16
第 一 种 情 况 第一种情况
答 案 为 x ∗ ( R R − R ) ∗ ( i d − L ) 答案为x * (RR - R) * (id - L) x(RRR)(idL)
在 [ i d , R ] 区 间 外 面 但 是 不 超 过 [ L , R R ] 区 间 在[id,R]区间外面但是不超过[L,RR]区间 [id,R][L,RR]
因 此 一 共 有 ( R R − R ) ∗ ( i d − L ) 个 区 间 满 足 第 二 大 值 等 于 x 因此一共有 (RR - R) * (id - L)个区间满足第二大值等于x (RRR)(idL)x

同 理 同理
在这里插入图片描述
第 二 种 情 况 第二种情况
答 案 为 x ∗ ( L − L L ) ∗ ( R − i d ) 答案为x * (L- LL) * (R - id) x(LLL)(Rid)

其 实 想 到 这 一 步 不 难 其实想到这一步不难
还 剩 下 2 个 难 题 还剩下2个难题 2
第 一 个 问 题 第一个问题
如 何 用 l o g n 的 时 间 之 内 找 到 左 右 两 边 比 它 大 的 下 标 如何用logn的时间之内找到左右两边比它大的下标 logn

肯 定 是 二 分 肯定是二分
怎 么 二 分 ? 怎么二分?
一 个 大 致 的 想 法 是 枚 举 的 当 前 答 案 是 x 一个大致的想法是枚举的当前答案是x x
左 右 2 边 的 数 都 比 它 大 左右2边的数都比它大 2

因 此 是 不 是 可 以 从 大 到 小 枚 举 答 案 因此是不是可以从大到小枚举答案
然 后 依 次 在 s e t 里 面 插 入 下 标 然后依次在set里面插入下标 set
二 分 找 到 即 可 二分找到即可

第 二 个 问 题 第二个问题
L L , L , R , R R 可 能 不 存 在 LL,L,R,RR可能不存在 LL,L,R,RR
边 界 问 题 如 何 讨 论 ? 边界问题如何讨论?
最 开 始 的 时 候 插 入 0 , 0 , n + 1 , n + 1 即 可 最开始的时候插入0,0,n+1,n+1即可 0,0,n+1,n+1

感 兴 趣 的 可 以 推 一 下 为 什 么 感兴趣的可以推一下为什么

这 题 的 细 节 问 题 是 真 的 颇 多 这题的细节问题是真的颇多
对 码 力 要 求 和 思 维 能 力 要 求 很 高 对码力要求和思维能力要求很高
一 定 要 认 真 推 一 下 所 有 的 过 程 以 及 这 题 为 什 么 要 这 么 想 一定要认真推一下所有的过程以及这题为什么要这么想
以 及 对 时 间 复 杂 度 有 个 清 晰 的 认 识 以及对时间复杂度有个清晰的认识
时间复杂度 O n l o g n Onlogn Onlogn

#include <bits/stdc++.h>
#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define der(i,a,b) for(int i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;

int n ;
int p[N] ;
int pos[N] ;

signed main()
{
    cin >> n ;
    fer(i,1,n) sf(p[i]) , pos[p[i]] = i ;
    
    multiset<int> se ;
    int res = 0 ;
    se.insert(0) ;
    se.insert(0) ;
    se.insert(n + 1) ;
    se.insert(n + 1) ;
    
    der(i,n,1)
    {
        auto x = i ;
        auto id = pos[x];
        auto r = *se.lower_bound(id) ;
        auto rr = *next(se.lower_bound(id));
        auto l = *prev(se.lower_bound(id));
        auto ll = *prev(se.lower_bound(id) , 2);
        
        res += ((id - l) * (rr - r) + (r - id) * (l - ll)) * x ;
        se.insert(id) ; 
    }
    
    cout << res ;
    return 0;
}

Bob和Alice(6)

思路
其 实 思 路 就 在 题 目 中 其实思路就在题目中
按 照 题 目 说 的 模 拟 即 可 按照题目说的模拟即可
一 开 始 选 的 病 毒 的 属 性 值 一 定 是 样 例 中 最 大 的 那 一 个 一开始选的病毒的属性值一定是样例中最大的那一个
然 后 循 环 n 秒 然后循环n秒 n
每 次 二 分 找 到 小 于 这 个 病 毒 属 性 值 的 最 大 的 那 一 个 病 毒 每次二分找到小于这个病毒属性值的最大的那一个病毒
然 后 把 这 个 病 毒 删 除 然后把这个病毒删除
找 不 到 说 明 不 能 满 足 题 意 找不到说明不能满足题意
直 接 r e t u r n 0 即 可 直接return0即可 return0

因 此 题 目 涉 及 到 删 除 及 二 分 操 作 因此题目涉及到删除及二分操作
可 以 用 s t l 中 的 m u l t i s e t 完 美 解 决 可以用stl中的multiset完美解决 stlmultiset
时间复杂度 O n l o g n Onlogn Onlogn

#include <bits/stdc++.h>
#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define der(i,a,b) for(int i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int> 
#define int long long 
#define pb push_back
#define y second 
#define x first 
using namespace std;
const int N = 1e6 + 10 , M = 2010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;

int n ;
int s[N] ;
multiset<int> q ;
vector<int> a , b ;

signed main()
{
    cin >> n ;
    fer(i,0,(1 << n) - 1) sf(s[i]) , q.insert(s[i]);
    auto it = --q.end() ;
    a.pb(*it) , q.erase(it) ;
    
    for(int i = 0 ; i < n ; i ++)
    {
        for(auto j : a)
        {
            auto it = q.lower_bound(j) ; 
            if(it == q.begin()) { puts("No") ; return 0 ;}
            it -- ;
            b.pb(*it) , q.erase(it) ;
        }
        
        for(auto j : b) a.pb(j) ;
        b.clear() ;
    }
    
    puts("Yes") ;
    return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值