首页 > 其他分享 >Codeforces Round 912 (Div

Codeforces Round 912 (Div

时间:2024-01-26 19:15:22浏览次数:30  
标签:std boy Lazy int Codeforces long 数组 Div 912

A Halloumi Boxes

题目大意

给定一个数组A,我们可以对数组惊醒多次操作,操作如下:
我们可以将数组中的某一段倒置,但是长度不能超过K,例如:反转子数组意味着选择两个索引i和j(其中 1 <= i <= j <= n )
并将数组

\[a_1,a_2,…,a_n \]

改为

\[a_1,a_2,…,a_{i−1},a_{j},a_{j−1},…,a_{i},a_{j+1},…,a_{n-1},a_n \]

(j − i + 1 <= k )

分析

由于可以操作多次,那么我们可以判断下k是否为1:

  1. 若k = 1时, 我们只能反转一个元素,显然是无效的, 我们就只需要判断数组是否为有序
  2. 若k > 1时,显然是可行的

代码

#include <bits/stdc++.h>

#define int long long
#define endl '\n'

void solve () {
    int n, k;
    std::cin >> n >> k;
    std::vector<int> a(n, 0), b(n, 0);
    for(int i = 0 ; i < n ; i ++) 
        std::cin >> a[i], b[i] = a[i];

    std::sort(b.begin (), b.end ());
    bool f = true;
    for(int i = 0 ; i < n ; i ++){
        if(a[i] != b[i]){
            f = false;
            break;
        }
    }
    if(f) 
        std::cout << "YES" << endl;
    else {
        if(k > 1)
            std::cout << "YES" << endl;
        else 
            std::cout << "NO" << endl;
    }
}


signed main () {
    std::ios::sync_with_stdio (false);
    std::cin.tie (nullptr), std::cout.tie (nullptr);
    int Lazy_boy_ = 1;
    std::cin >> Lazy_boy_;
    while (Lazy_boy_--)
        solve ();
    return 0;
}

B StORage room

题目大意

给定一个数n,和一个n*n的数组M,数组

\[M_{i,j} \]

表示为:

\[M_{i,j} = \begin{cases} a_i|a_j,(i \not= j)\\\\ 0, (i == j)\end{cases}(M_{i,j} < 2 ^{30}) \]

让我们判断是否存在这样的一个数组a满足上式,若存在输出YES和数组a
否则输出NO

分析

现在我有两个数x, y,如果我将这两个数进行或运算后(w = x | y), 在二进制状态下xy在某一位上有一个为1,则该位为1
通过这个我们可以发现在

\[M_i \]

中,

\[M_{i,0} = a_i | a_0, M_{i,1} = a_i | a_1, ........, M_{i,n - 1} = a_i | a_{n - 1} \]

, 我们可以通过与运算将

\[a_i \]

计算出来, 但是在运算时我们需要排除

\[M_{i,j}(i==j) \]

;
在计算完后我们可以遍历一次M数组,判断

\[M_{i,j}=a_i|a_j(i \not= j) \]

代码

#include <bits/stdc++.h>

#define int long long
#define endl '\n'

void solve () {
    int n;
    std::cin >> n;
    std::vector<int> a(n, 0);
    std::vector<std::vector<int> > m(n, std::vector<int> (n, 0));
    for(int i = 0 ; i < n ; i ++){
        int x = -1;
        for(int j = 0;j < n;j ++){
            std::cin >> m[i][j];
            if(i != j){
                if(x == -1)
                    x = m[i][j];
                x &= m[i][j];
            }
        }
        a[i] = x;
    }
    if(n == 1){//特殊情况,可任意输出一个数
        std::cout << "YES" << endl << 1 << endl;
        return ;
    }
    auto check = [&] (){
        for(int i = 0 ; i < n ; i ++){
            for(int j = 0 ; j < n ; j ++){
                int x = a[i] | a[j];
                if(m[i][j] != x && i != j){
                    return false;
                }
            }
        }
        return true;
    };
    if(check()){
        std::cout << "YES" << endl;
        for(int i = 0 ; i < n ; i ++)
            std::cout << a[i] << " ";
        std::cout << endl;
    }
    else 
        std::cout << "NO" <<endl;
}


signed main () {
    std::ios::sync_with_stdio (false);
    std::cin.tie (nullptr), std::cout.tie (nullptr);
    int Lazy_boy_ = 1;
    std::cin >> Lazy_boy_;
    while (Lazy_boy_--)
        solve ();
    return 0;
}

C Theofanis' Nightmare(贪心)

题目大意

给定一个数组a,大小为n,现在将数组a分割成几个非空子数组,并且保证每个元素只在一个一个子数组中,例如,数组 [1,−3,7,−6,2,5]可以划分为 [1][−3,7][−6,2][5]
这种分割的值等于

\[\sum_{i=1}^k i*sum_i \]

,其中k是我们将数组分割成的子数组的个数,

\[sum_i \]

是第i个子数组的和。
这个数组的值为

\[[1][−3,7][−6,2][5]=1\times 1+2\times (−3+7)+3\times (−6+2)+4\times5=17 \]

现在让我们求分割的最大值为多少?

分析

先考虑每个子段的数字贡献,i* sum_i也可以转化为该子段中每个数字被加上了i次。那么就可以把乘法转化为加法。
然后考虑怎么划分子段最优,如果从前往后考虑,很难判断是否该将当前数字划分为一个新子段的起点。
因此,需要从后往前遍历,统计i∼n之间的数字总和,为了使答案尽可能大,那么只要当前数字总和大于等于0,就可以将当前位置划分给一个新的子段起点。
此时,划分出一个新的起点后,那么后面所有的数字均需要再被加上一次,不难发现,此时要加上的就是维护的数字总和。
由于第一个元素也可能被划分到一个新的子段中,为了避免重复计算,当遍历到第一个元素时,必须将当前元素视为子段起点,加上维护的数字总和。

代码

#include <bits/stdc++.h>

#define int long long
#define endl '\n'

void solve () {
    int n;
    std::cin >> n;
    std::vector<int> a(n, 0);
    for(int i = 0 ; i < n ; i ++)
        std::cin >> a[i];
    int ans = 0, w = 0;
    for(int i = n - 1; i >= 0 ; i --){
        w += a[i];
        if(i == 0 || w > 0)
            ans += w; 
    }
    std::cout << ans << endl;
}


signed main () {
    std::ios::sync_with_stdio (false);
    std::cin.tie (nullptr), std::cout.tie (nullptr);
    int Lazy_boy = 1;
    std::cin >> Lazy_boy;
    while (Lazy_boy--)
        solve ();
    return 0;
}
#include <bits/stdc++.h>

#define int long long
#define endl '\n'

void solve () {
    int n;
    std::cin >> n;
    std::vector<int> a(n + 1, 0ll), s(n + 1, 0ll);
    for(int i = 1 ; i <= n ; i ++)
        std::cin >> a[i], s[i] = s[i - 1] + a[i];
    int ans = 0, w = 0;
    for(int i = 1; i <= n ; i ++){
        if(i == 1 || s[n] - s[i - 1] >= 0) 
            w ++;
        ans += w * a[i];
    }
    std::cout << ans << endl;
}


signed main () {
    std::ios::sync_with_stdio (false);
    std::cin.tie (nullptr), std::cout.tie (nullptr);
    int Lazy_boy_ = 1;
    std::cin >> Lazy_boy_;
    while (Lazy_boy_--)
        solve ();
    return 0;
}

D1 Maximum And Queries (easy version)

题目大意

给出一个长度为n的数组a,并进行q次询问,每次询问为:
你可以进行k次操作,每次从数组a中选择一个元素,让这个元素 + 1
问:经过q次操作后,

\[a_1,a_2,.....,a_n \]

的与的最大值是多少
注:每次询问都是独立的,不会保留前面询问的操作结果。

分析

由于每次询问都是独立的,那么修改不能在原数组上进行,需要将原数组元素复制到其他数组中再进行操作。
题目数据规定了

\[n\times q≤10^5 \]

,那么可以认为最大的数据就是对长度为

\[10^5 \]

的数组进行一次询问。
由于给出的

\[k≤10^{18} \]

,那么当数组中只有一个元素时,最大可能的结果为

\[10^{18}+10^6≈2^{60} \]

,因此需要一个大于60的数组记录与运算后的结果每位二进制数是多少。
对于每次询问,从二进制高位开始往低位进行遍历,每次检查当前剩余的k是否还能将数组中所有数的当前二进制位修改为1
如果可以,进行修改,并记录在答案数组中,如果不行,继续遍历更低的二进制位。
结束修改后,将数组中记录的信息转化为十进制数即可。

本题数据较大,需要注意使用左移运算需要使用1ll将1转化为long long类型再进行运算,计算花费时也要考虑如果超过操作次数就该退出检查,避免数据溢出。

代码

#include <bits/stdc++.h>

#define int long long
#define endl '\n'
const int N = 1e5 + 5;

int a[N], b[N], ans[105];
int n, q;

int getCost(int x, int k) {
    int cost = 0;
    for (int j = 1; j <= n; j++) {
        if ((b[j] & (1ll << x)) == 0) {
            //使用位运算计算将b[j]的第x位二进制修改为1需要加上多少
            cost += (1ll << x) - ((1ll << (x + 1)) - 1ll & b[j]);
        }
        if (cost > k) return cost; //超过k就返回,避免数据溢出
    }
    return cost;
}

void solve() {
    std::cin >> n >> q;
    for(int i = 1; i <= n ; i ++)
        std::cin >> a[i];
    while(q --){
        int k;
        std::cin >> k;
        memset(ans, 0, sizeof(ans));
        for (int i = 1; i <= n; i++) 
            b[i] = a[i];
        for (int i = 60; i >= 0; i--) {//检查第i位结果与运算的结果是否可能为1
            int cost = getCost(i, k);
            if (cost <= k) {//花费在操作次数范围内
                ans[i] = 1;//与运算结果可以为1
                k -= cost;
                for (int j = 1; j <= n; j++) {
                    if ((b[j] & (1ll << i)) == 0) {
                        //通过或运算将2^i位修改为1,再通过与运算将后面数字清0
                        b[j] = ((b[j] | (1ll << i)) & (1ll << i));
                    }
                }
            }
        }
        int res = 0;
        for (int i = 0; i <= 60; i++)
            res |= (ans[i] << i);//这里ans[i]如果不是long long类型也会发生溢出
        std::cout << res << endl;
    }
}


signed main () {
    std::ios::sync_with_stdio (false);
    std::cin.tie (nullptr), std::cout.tie (nullptr);
    int Lazy_boy = 1;
    // std::cin >> Lazy_boy;
    while (Lazy_boy--)
        solve ();
    return 0;
}

标签:std,boy,Lazy,int,Codeforces,long,数组,Div,912
From: https://www.cnblogs.com/Lazyboyjdj/p/17990490

相关文章

  • Codeforces Round 913 (Div
    ARook题目大意给一个国际象棋棋盘,有t次询问,每次询问给定一个棋子坐标s例如d4.问:输出这个棋子上下左右四个方向的坐标解题思路两个for循环暴力求解代码#include<bits/stdc++.h>#defineintlonglong#defineendl'\n'constintINF=0x3f3f3f3f;voidso......
  • Codeforces Round 914 (Div
    AForked!题目大意给定王后和国王的位置,马可以先朝一个方向走a步,再朝另一个方向走b步问:马有多少个位置可以同时走到皇后和国王解题思路就无脑遍历一下马能走到国王和皇后的位置然后再判断下有没有相同的位置代码#include<bits/stdc++.h>#defineintlonglong......
  • Codeforces Round 916 (Div
    AProblemsolvingLog题目描述给一个整数n,字符串s,字符串中s[i]表示第i分钟解决第s[i]题.问题A需要1分钟解决,问题B需要2分钟解决,以此类推.问:可以解决多少题?解题思路遍历字符串,统计问题A--Z用了多少时间解决.最后在遍历数组,判断问题A--Z是否满足解决时间.代......
  • Educational Codeforces Round 159 (Rated for Div
    EducationalCodeforcesRound159(RatedforDiv.2)ABinaryImbalance题目大意给定一个长度为n的一个01字符串,我们执行以下操作:当s[i]!=s[i+1]在中间插入0问:是否可以实现0的个数大于1的个数解题思路由题意可以明显看出只要有0就可以实现。下面简单分析下:0的个数大......
  • Educational Codeforces Round 160 (Rated for Div
    ARatingIncreas题目大意给定一个数字,让我们拆分成两个数,这两个数满足以下条件:a<b.两个数没有前缀0.问:输出满足条件的数a,b.解题思路直接暴力循环这个数的位数次,若满足a<b,再判断两个数的位数和是否与拆分前相同.代码#include<bits/stdc++.h>#defin......
  • Educational Codeforces Round 161 (Rated for Div
    ATrickyTemplate题目描述给一个数字n和三个长度为n的字符串a,b,c。找一个模板使得字符串a,b匹配,而c不匹配,是否存在这样一个模板.匹配的定义是:当模板字母为小写时,两个字符串字符相同,为大写时,两个字符不同,这样的两个字符串则匹配解题思路我们可以直接得出当a字符串......
  • hey_left 17 Codeforces Round 817 (Div. 4)
    题目链接A.把标准字符串和输入字符串排序,看是否相等#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;voidsolve(){intn;cin>>n;stringt;cin>>t;strings="Timur";sort(s.begin(),s.end());......
  • hey_left 16 Codeforces Round 827 (Div. 4)
    题目链接A.判最大的数是不是另外两个数的和#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;voidsolve(){inta,b,c;cin>>a>>b>>c;cout<<(max({a,b,c})==a+b+c-max({a,b,c})?"YES":"......
  • CF1912E
    最近正在练构造题,写篇题解分享一下实现的细节。核心过程大胆猜测,不难发现一个重要的结论:假设有一个式子\(a+a-0\),则其从左往右的结果为\(2a\),从右往左的结果为\(0\)。有了这个结论,我们就可以考虑用两段这样的式子来分别求得\(p\)和\(q\)。接下来分析细节。上述结论的使用......
  • Codeforces 1667E Centroid Probabilities
    这个连边方式就可以理解为\(1\)为根,点\(u\)的父亲\(fa_u\)满足\(fa_u<u\)。重心有不止一种表示法,考虑用“子树\(siz\ge\lceil\frac{n}{2}\rceil\)最深的点”来表示重心。令\(m=\lceil\frac{n}{2}\rceil\),\(f_i\)为节点\(i\)的\(siz\gem\)的方案数。考虑枚......