Codeforces Round #780 (Div. 3) A-F2题解

Posted ZZXzzx0_0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #780 (Div. 3) A-F2题解相关的知识,希望对你有一定的参考价值。

A. Vasya and Coins

题意
给你 a a a个一块钱的硬币和 b b b个两块钱的硬币,求最大不能被凑出来的正整数

思路

  • 如果 a a a 0 0 0,说明 1 1 1我们无论无何也凑不出来

  • 如果 a a a存在,说明 [ 1 , a + 2 ∗ b ] [1,a+2*b] [1,a+2b]中的任何一个正整数都可以凑出来,答案即为 a + 2 b + 1 a+2b+1 a+2b+1

时间复杂度 O t Ot Ot

#define cf int _; cin>> _; while(_--)
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ; // mod = 998244353 ;
int n , m ;
int a[N] ;
 
signed main()

    cf
    
        int a , b ;
        cin >> a >> b ;
        if(a >= 1)
            cout << a + 2 * b + 1 << '\\n' ;
        else 
        
            puts("1") ;
        
    
    return 0 ;

B. Vlad and Candies

题意
给你 n n n个数的数组,每次你可以任选一个最大的数 a [ i ] a[i] a[i],使其减一

但是不能连续选 2 2 2个下标相同的数,求是否可以都减为 0 0 0

思路

  • 显然当最大值减去次大值 > = 2 >=2 >=2
    说明无论无何也不可以都减为 0 0 0

在证明其他情况一定可以的充要性

  • 我们假设最大值为 d 1 d1 d1,次大值为 d 2 d2 d2
    我们先减去 d 1 d1 d1,在减 d 2 d2 d2,然后不断重复
    在减去的过程中,如果出现了与其他数相等的情况
    依次减去其他相等的数,这样子一定可以保证都可以减为 0 0 0

时间复杂度 O n l o g n Onlogn Onlogn

#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define cf int _; cin>> _; while(_--)
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ; // mod = 998244353 ;
int n , m ;
int a[N] ;
 
signed main()

    cf
    
        cin >> n ;
        fer(i,1,n) cin >> a[i] ;
        sort(a + 1 , a + 1 + n) ;
        if(n == 1) 
        
            cout << (a[1] == 1 ? "YES" : "NO") << '\\n' ;
        
        else
        
            cout << (a[n] - a[n - 1] >= 2 ? "NO" : "YES") << "\\n" ;
        
    
    return 0 ;

C. Get an Even String

题意
给你一个字符串,求将其变为 a a c c x x f f e e . . . . . aaccxxffee..... aaccxxffee.....任意字母都连续出现偶数个数的情况下你需要删除字母个数的最小值

n < = 2 e 5 n <= 2e5 n<=2e5

思路
直接求不好求,不如换个思路

  • 原题等价于n-最大任意字母都连续出现偶数情况下的字符串长度

求最大长度遍历一遍即可

时间复杂度 O n On On

inline void de(auto x) cout << x << "\\n" ;
#define cf int _; cin>> _; while(_--)
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ; // mod = 998244353 ;
int n , m ;
int a[N] ;
char s[N] ;
 
signed main()

    cf
    
        cin >> s + 1 ;
        n = strlen(s + 1) ;
        bitset<200> st ;
        st[s[1]] = 1 ;
        int res = 0 ;
        for(int i = 2 ; i <= n ; i ++)
        
            if(st[s[i]])
            
                res += 2 ;
                st.reset() ;
            
            else
            
                st[s[i]] = 1 ;
            
        
        
        de(n - res) ;
    
    return 0 ;

D. Maximum Product Strikes Back

题意
给你一个 n n n个数的数组
你可以删去任意数组前缀或者任意数组后缀

求删去之后使剩下的子数组的乘积最大
输出前缀删除的个数以及后缀删去的个数

题目规定空的子数组[]的乘积为1

n < = 2 e 5 , ∣ a [ i ] ∣ < = 2 n <= 2e5 , |a[i]|<=2 n<=2e5,a[i]<=2

思路
一道比较考验码力 的题,不知道有没有更简单的方法
首先题目定义了空的子数组[]的乘积为 1 1 1

说明最后剩下的子数组一定不能出现 0 0 0
根据此性质我们可以把数组分为
0.....0......0......0.....0 0 ..... 0 ...... 0......0.....0 0.....0......0......0.....0
特殊定义 a [ 0 ] = 0 , a [ n + 1 ] = 0 a[0] = 0 , a[n + 1] = 0 a[0]=0,a[n+1]=0

对每一个 0.......0 0.......0 0.......0
可以分 2 2 2种情况讨论

  • 情况 1 1 1,区间负数个数为偶数,说明此区间乘积必定为正,更新一下最大值
  • 情况 2 2 2,区间负数个数为奇数,二分找到这个区间的第一个负数最后一个负数下标,更新一下最大值

时间复杂度 O n l o g n Onlogn Onlogn

#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define lb lower_bound
#define ub upper_bound
inline void de2(auto a , auto b) cout << a << " " << b << "\\n" ;
#define cf int _; cin>> _; while(_--)
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ; // mod = 998244353 ;
int n , m ;
int a[N] ;
int s[N] ; // s[i]表示[1,i]中负数的个数
int ss[N] ; // ss[i]表示[1,i]中a[i]绝对值=2的个数
int res , ll , rr ;
 
void get(int l , int r)

    int x = s[r] - s[l - 1] ;
    int sum = ss[r] - ss[l - 1] ;
    if(sum > res && x % 2 == 0)
    
        res = sum ;
        ll = l - 1 , rr = n - r ;
    

 
signed main()

    cf
    
        cin >> n ;
        vector<int> v ;
        fer(i,1,n) cin >> a[i] , s[i] = s[i - 1] + (a[i] < 0) , ss[i] = ss[i - 1] + (abs(a[i]) == 2) ;
        a[0] = 0 , a[n + 1] = 0 ;
        fer(i,0,n+1) 
            if(a[i] == 0)
                v.push_back(i) ;
                
        multiset<int> q ; // set里面放所有负数的下标
        fer(i,1,n)
            if(a[i] < 0)
                q.insert(i) ;
                
        res = -1e9 ;
        ll = 1 , rr = n - 1 ;
        for(int i = 0 ; i + 1 < sz(v) ; i ++)
        
            int l = v[i] + 1 , r = v[i + 1] - 1 ;
            int x = s[r] - s[l - 1] ;
            if(x % 2 == 0)
            
                get(l,r)
            
            else
            
                auto it = q.lb(l) ;
                get(*it + 1 , r) ;
                
                it = q.ub(r) ;
                -- it ;
                get(l , *it - 1) ;
            
        
        
        de2(ll , rr) ;
    
    return 0 ;

E. Matrix and Shifts

题意
给你 n ∗ n n*n nn的数组,你可以进行以下操作任意次

  • 将第一行移动到最后一行
  • 将最后一行移动到第一行
  • 将第一列移动到最后一列
  • 将最后一列移动到第一列

问你怎么操作使得
该数组与另外一个n*n的数组(主对角线都是1,其余全为0)不同的数的个数最小

思路
假设此数组
1 1 1总个数 s u m sum sum
与另外一个数组重合 1 1 1的个数为 r e s res res
那么

  • 主对角线其余地方不同的数的个数为 s u m − r e s sum-res sumres
  • 主对角线上不同的数的个数为 n − r e s n-res nres

答案即为 s u m + n − 2 ∗ r e s sum + n - 2 * res sum+n2res
因为要最小化结果, s u m , n sum,n sum,n都为常数
等价于求 r e s res res最大值

我们可以枚举向右的偏移量 i i i和第 j j Codeforces Round #780 (Div. 3)(ABCDEF1F2)

Codeforces Round #780 (Div. 3)(ABCDEF1F2)

Codeforces Round #780 (Div. 3)(ABCDEF1F2)

Codeforces Round #780 (Div. 3) A-F2题解

Codeforces Round #780 (Div. 3) A-F2题解

Codeforces Round #780 (Div. 3) A-F2题解