Codeforces Round #735 (Div. 2) 题解(A-D)

Codeforces Round #735 (Div. 2) 题解(A-D)

A. Cherry

题目大意:

有一个长度为 n n n的整数数组 a a a。找出 m a x ( a l , a l + 1 , . . . , a r ) × m i n ( a l , a l + 1 , . . . a r ) , 1 ≤ l < r ≤ n max(a_l,a_{l+1},...,a_r)\times min(a_l,a_{l+1},...a_{r}),1\le l <r \le n max(al,al+1,...,ar)×min(al,al+1,...ar),1l<rn的最大值。

解题思路:

通过观察样例,我们可以大胆地猜测最优解的区间长度不会超过 2 2 2,所以我们只用遍历一遍数组即可,时间复杂度 O ( n ) O(n) O(n)

现在简单论证一下为什么这种做法是正确的:

如果存在一个区间 [ l , l + 2 ] [l,l+2] [l,l+2]是优于 [ l , l + 1 ] [l,l+1] [l,l+1] [ l + 1 , l + 2 ] [l+1,l+2] [l+1,l+2]的,那么区间 [ l , l + 1 ] [l,l+1] [l,l+1]的最大值和最小值一定是 a l a_l al a l + 2 a_{l+2} al+2

如果 a l a_l al是最大值的话,因为 a l + 1 ≥ a l + 2 a_{l+1}\ge a_{l+2} al+1al+2,那么一定存在 a l × a l + 1 ≥ a l × a l + 2 a_l\times a_{l+1}\ge a_l\times a_{l+2} al×al+1al×al+2

同理,如果 a l + 2 a_{l+2} al+2是最大值的话,那么一定存在 a l + 2 × a l + 1 ≥ a l × a l + 2 a_{l+2}\times a_{l+1}\ge a_l\times a_{l+2} al+2×al+1al×al+2

所以对于区间长度大于 2 2 2的区间,我们一定能找出不弱于当前区间的区间长度为 2 2 2的区间。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int a[N];
int n;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        LL res=0;
        for(int i=1;i<n;i++){
            res=max(res,(LL)a[i]*a[i+1]);
        }
        printf("%lld\n",res);
    }
    return 0;
}

B. Cobb

题目大意:

对于一个长度为 n n n的整数数组 a a a。找出 ∀    1 ≤ i < j ≤ n , i × j − k × ( a i ∣ a j ) \forall \;1\le i<j\le n,i\times j-k\times(a_i|a_j) 1i<jn,i×jk×(aiaj)的最大值,其中 ∣ | 表示位运算中的或运算。

数据范围: 1 ≤ n ≤ 1 0 5 , 1 ≤ k ≤ min ⁡ ( n , 100 ) , 0 ≤ a i ≤ n 1\le n\le10^5,1\le k \le \min(n,100),0\le a_i\le n 1n105,1kmin(n,100),0ain.

解题思路:

由于 n n n数据范围的限制,如果本题用 O ( n 2 ) O(n^2) O(n2)的暴力做法是会 T L E TLE TLE的。

通过观察 i × j − k × ( a i ∣ a j ) i\times j-k\times(a_i|a_j) i×jk×(aiaj)这个结构,我们发现对于前半部分的 i × j i\times j i×j,我们一定是会在 ( n − 1 , n ) (n-1,n) (n1,n)这一对取到最大值,又因为 0 ≤ a n − 1 ∣ a n ≤ 2 × n 0\le a_{n-1}|a_n\le 2\times n 0an1an2×n ( n − 1 , n ) (n-1,n) (n1,n)这一对的最小值是 min ⁡ ( n − 1 , n ) = ( n − 1 ) × n − k × 2 × n = n 2 − 2 × k × n − n \min(n-1,n)=(n-1)\times n-k\times2\times n=n^2-2\times k\times n-n min(n1,n)=(n1)×nk×2×n=n22×k×nn

那么我们考虑对于任何一对 ( i , j ) (i,j) (i,j),其中 i < j i<j i<j。对于包含 i i i的某对而言,能取得的最大值就是 j = n j=n j=n并且 a i ∣ a j = 0 a_i|aj=0 aiaj=0 的时候,此时能取得的最大值 max ⁡ ( i , j ) = i × n \max(i,j)=i\times n max(i,j)=i×n

对于上述得到的信息,我们可以选择将那些没有希望大于 m i n ( n − 1 , n ) min(n-1,n) min(n1,n)的pair​过滤掉,

m a x ( i , j ) ≤ m i n ( n − 1 , n ) ⇒ i × n ≤ n 2 − 2 × k × n − n ⇒ i < = n − 2 × k − 1 max(i,j)\le min(n-1,n) \Rightarrow i\times n\le n^2 - 2\times k \times n -n \Rightarrow i<=n-2\times k-1 max(i,j)min(n1,n)i×nn22×k×nni<=n2×k1

所以我们只用考虑 i ≥ n − 2 ∗ k i\ge n-2*k in2k这一部分pair就行,时间复杂度 O ( k 2 ) O(k^2) O(k2)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int a[N];
int n,k;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        LL res=-1e9;
        for(int i=max(1,n-2*k);i<=n;i++)
            for(int j=i+1;j<=n;j++)
                res=max(res,(LL)i*j-k*(a[i]|a[j]));
        printf("%lld\n",res);
    }
    return 0;
}

C. Mikasa

题目大意:

给定整数 n n n m m m,找出序列 n ⊕ 0 , n ⊕ 1 , . . . , n ⊕ m n\oplus 0,n\oplus1,...,n\oplus m n0,n1,...,nm中未出现的最小非负整数,其中 ⊕ \oplus 是位运算中的异或运算。

解题思路:

转换一下思路,可以将原问题转换为找一个最小的整数k使得 n ⊕ k > m n\oplus k>m nk>m

p = m + 1 p=m+1 p=m+1,在使得k尽可能小的情况下,我们从高位向低位考虑以下四种情况,其中 n i , p i , k i n_i,p_i,k_i ni,pi,ki分别代表 n , p , k n,p,k n,p,k二进制表示下的第 i i i位:

  1. n i = 0 , p i = 0 , 那 么 k i = 0 n_i=0,p_i=0,那么k_i=0 ni=0,pi=0,ki=0
  2. n i = 0 , p i = 1 , 那 么 k i = 1 n_i=0,p_i=1,那么k_i=1 ni=0,pi=1,ki=1
  3. n i = 1 , p i = 0 , 那 么 k i = 0 n_i=1,p_i=0,那么k_i=0 ni=1,pi=0,ki=0
  4. n i = 1 , p i = 1 , 那 么 k i = 0 n_i=1,p_i=1,那么k_i=0 ni=1,pi=1,ki=0

我们发现只有当 n i = 0 , p i = 1 n_i=0,p_i=1 ni=0,pi=1的时候,我们才需要将 k i k_i ki变为1。并且为了使得k尽可能小,一但满足 n ⊕ k ≥ p n\oplus k\ge p nkp就要停止循环。

所以只需要从高位向低位枚举 n n n m m m的所有二进制位,时间复杂度 O ( l o g 2 n ) O(log_2n) O(log2n)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        m++;
        int res=0;
        for(int i=30;i>=0&&n<m;i--){
            if(!(n>>i&1)&&m>>i&1) n|=1<<i,res|=1<<i;
        }
        printf("%d\n",res);
    }
    return 0;
}

D. Diane

题目大意:

给定一个整数 n n n。构造出一个长度为 n n n由小写字母组成的字符串,其中对于字符串中的任何一个子串在字符串中出现奇数次。

解题思路:

对于连续的 k k k a a a,会产生 k k k个"a", k − 1 k-1 k1个"aa", k − 2 k-2 k2个"aaa"…,每种字符串的数量是奇偶交替的。

那么我们可以选择再添加连续的 k − 1 k-1 k1 a a a,这一串连续的会产生 k − 1 k-1 k1个"a", k − 2 k-2 k2个"aa"…,刚好将上面连续的 k k k a a a产生的偶数次字符串修正为奇数次。

当然这两个字符串中间需要加字母来隔开,我们发现 k + k − 1 k+k-1 k+k1永远是一个奇数,那么如果 n n n是奇数的话,我们就需要在中间添上两个字母作为挡板, n n n是偶数的话就只用添上一个字母。

所以我们对于 n n n是奇数的情况,可以构造出 a a a . . . a a a ⏟ k b c a a a . . . a a a ⏟ k − 1 \underbrace{aaa...aaa}_{k} bc\underbrace{aaa...aaa}_{k-1} k aaa...aaabck1 aaa...aaa,当n=1的时候需要特判一下。

n n n是偶数的情况,可以构造出 a a a . . . a a a ⏟ k b a a a . . . a a a ⏟ k − 1 \underbrace{aaa...aaa}_{k} b\underbrace{aaa...aaa}_{k-1} k aaa...aaabk1 aaa...aaa

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        if(n==1){
            puts("a");
            continue;
        }
        for(int i=0;i<n/2-1;i++) printf("a");
        printf(n%2?"bc":"b");
        for(int i=0;i<n/2;i++) printf("a");
        puts("");
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值