首页 > 其他分享 >Atcoder 269

Atcoder 269

时间:2022-09-21 00:27:02浏览次数:69  
标签:std Atcoder int tt cin long ++ 269

T1:计算(a + b) * (c - d) 输出字符串

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int tt = 1; //std::cin >> tt;
 
    while(tt--){
        int a, b, c, d; 
        std::cin >> a >> b >>c >> d;
        std::cout << (a + b) * (c - d) << '\n';
        std::cout << "Takahashi" << '\n';
    }
 
    return 0;
}

T2:给定只含". #"字符矩阵,其中存在一个子矩阵完全由"#"组成,求该子矩阵的上下行数和左右列数
显然 上行数必定是所有"#"row的最小值,其它类似

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int tt = 1; //std::cin >> tt;
 
    while(tt--){
        std::vector<std::string> s(10);
        for(int i = 0; i < 10; ++i){
            std::cin >> s[i];
        }
 
        int a = 9, b = 0, c = (int)s[0].size() - 1, d = 0;
        for(int i = 0; i < 10; ++i){
            int l, r;
            for(int j = 0; j < (int)s[j].size(); ++j){
                if(s[i][j] == '#'){
                    a = std::min(a, i);
                    b = std::max(b, i);
                    c = std::min(c, j);
                    d = std::max(d, j);
                }
            }
        }
        std::cout << a + 1 << ' ' << b + 1 << '\n' << c + 1 << ' ' << d + 1 << '\n';
    }
 
    return 0;
}

T3:求某个数的二进制意义下的子集

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    i64 n; std::cin >> n;
 
    std::vector<i64> a;
 
    for(i64 i = n; i; i = (i - 1) & n){
        a.push_back(i);
    }
    a.push_back(0);
 
    std::reverse(a.begin(), a.end());
 
    for(auto x : a){
        std::cout << x << '\n';
    }
 
    return 0;
}

T4:给定坐标位于蜂窝坐标内,求连通块数目
dfs求连通块即可

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;

std::vector<int> xx = {-1, -1, 0, 0, 1, 1}, yy = {-1, 0, -1, 1, 0, 1};
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int tt = 1; //std::cin >> tt;
 
    while(tt--){
        int n; std::cin >> n;
 
        std::vector<int> x(n), y(n);
        for(int i = 0; i < n; ++i){
            std::cin >> x[i] >> y[i];
        }
 
        std::vector<int> vis(n); int res = 0;
 
        std::map<std::pair<int, int>, int> q;
        for(int i = 0; i < n; ++i){
            q[{x[i], y[i]}] = i;
        }
        std::function<void(int, int)> dfs = [&] (int xz, int yz){
            for(int k = 0; k < 6; ++k){
                int xxx = xz + xx[k], yyy = yz + yy[k];
                if(!q.count({xxx, yyy})){
                    continue;
                }else{
                    int p = q[{xxx, yyy}];
                    if(vis[p]){
                        continue;
                    }else{
                        vis[p] = 1;
                        dfs(xxx, yyy);
                    }
                }
            }
        };
 
        for(int i = 0; i < n; ++i){
            if(!vis[i]){
                vis[i] = 1;
                dfs(x[i], y[i]);
                ++res;
            }
        }
        std::cout << res << '\n';
    }
    return 0;
}

T5:给定n * n矩阵,其中放置了n - 1个棋子,两两不可互相攻击,求某个位置使得所有点两两互不攻击,可以证明该位置必定唯一存在
根据互不攻击的特性,分别二分出该位置的row和col即可

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
 
std::vector<int> xx = {-1, -1, 0, 0, 1, 1}, yy = {-1, 0, -1, 1, 0, 1};
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int tt = 1; //std::cin >> tt;
 
    while(tt--){
        int n; std::cin >> n;
 
        int xx, yy;
        int a = 1, b = n, c = 1, d = n, x, y;
          while(a != b){
              int mid = (a + b) >> 1;
              std::cout << "? " << a << " " << mid << " " << c << " " << d << std::endl;
              std::cin >> x;
              int s1 = mid - a + 1 - x;
              if(s1 == 1){
                  b = mid;
              }else{
                  a = mid + 1;
              }
          }
          xx = a;
          a = 1, b = n;
          while(c != d){
              int mid = (c + d) >> 1;
              std::cout << "? " << a << " " << b << " " << c << " " << mid << std::endl;
              std::cin >> x;
              int s1 = mid - c + 1 - x;
              if(s1 == 1){
                  d = mid;
              }else{
                  c = mid + 1;
              }
          }
          yy = c;
          std::cout << "! " << xx << ' ' << yy << '\n';
    }

    return 0;
}

T6:给定A,B,C,D, M,求:

\[\sum_{i = A}^{B}\sum_{j = C}^{D}(i - 1) * M + j \,\, [(i + j) \& 1 == 0] \]

暴力肯定超时,考虑优化,考虑贡献来源分为i和j,且二者可以完全分离(分奇偶两种情况)
先考虑j的贡献:
1.若i为奇数,j只能取偶数
2.若i为偶数,j只能取奇数
此时j的贡献均可由等差数列求和公式快速求出
考虑i的贡献:
M提出,则也可经等差数列求和公式快速求出
然后注意求和后乘上个数后求和即可
tip:对于求贡献的题,尝试将其来源的不同分为完全独立的几部分,然后对于这些独立的部分进行优化求和,最后所有部分求和来达到优化的目的

点击查看代码
#include<bits/stdc++.h>

using i64 = long long;

constexpr int P = 998244353;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m; std::cin >> n >> m;

    int tt = 1; std::cin >> tt;

    while(tt--){
        int a, b, c, d; std::cin >> a >> b >> c >> d;

        int p1 = ((a + c) & 1) ? c + 1 : c, p2 = (p1 == c) ? c + 1 : c;
        int p3 = a - 1, p4 = a;

        int num1 = (((d - c + 1) & 1) == 1 && ((a + d) & 1) == 0) ? (d - c + 1) / 2 + 1: (d - c + 1) / 2, num2 = d - c + 1 - num1;
        int num3 = (b - a + 1) & 1 ? (b - a + 1) / 2 + 1 : (b - a + 1) / 2, num4 = b - a + 1 - num3;

        // std::cout << p1 << ' ' << p2 << ' ' << p3 << ' ' << p4 << '\n';
        // std::cout << num1 << ' ' << num2 << ' ' << num3 << ' ' << num4 << '\n';

        i64 sum1 = (i64)((p1 + num1 - 1) % P + P) % P * num1 % P, sum2 = (i64)((p2 + num2 - 1) % P + P) % P * num2 % P;
        i64 sum3 = (i64)((p3 + num3 - 1) % P + P) % P * num3 % P, sum4 = (i64)((p4 + num4 - 1) % P + P) % P * num4 % P;

        // std::cout << sum1 << ' ' << sum2 << ' ' << sum3 << ' ' << sum4 << '\n';

        i64 res {0};

        res = (res + (i64)(sum1 * num3) % P) % P;
        res = (res + (i64)(sum2 * num4) % P) % P;

        res = (res + (i64)sum3 * num1 % P * m % P) % P;
        res = (res + (i64)sum4 * num2 % P * m % P) % P;

        std::cout << res << '\n';
    }
}

T7:给定n张卡片,正面值为Ai,背面值为Bi,满足\(\sum_{i = 1}^{n}\)(Ai + Bi) = M
问最少的翻片数(正面变反面)使得翻片后正面值之和为i(i <= M)
一开始的数值之和为S,预处理出翻篇S的变化值,于是转换成为了一个0/1背包问题,但是会超时(O(NM)),考虑优化:
tip:dp的优化就哪几个方面,多深入理解吧,哎
预处理后,变化值为\(C_i\),对变化值相同的进行计数,记为\(F_i\)
优化性质:|F| <= 2\(\sqrt{M}\)

\[\sum_{i = 1}^{n}|C_i| <= M(*) \]

反证:|F| > 2\(\sqrt{M}\)

\[ |-\sqrt{M}| + |(-\sqrt{M} + 1)| + ... + |(\sqrt{M} - 1)| + |{\sqrt{M}}| > M \]

与(*)矛盾,故必有|F| <= 2 * \(\sqrt{M}\)
此时转化为了多重背包,时间复杂度为O(M\(\sum_{i = 1}^{|F|}Fi\)),已经可以通过此题
对于多重背包,我们还可以进行二进制优化,时间复杂度优化至为O(M\(\sum_{i = 1}^{|F|}\,log_{2}{F_i}\))

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
constexpr int P = 998244353;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int tt = 1; //std::cin >> tt;
 
    while(tt--){
        int n, m; std::cin >> n >> m;
 
        std::vector<int> c(n); int sum = 0;
        for(int i = 0; i < n; ++i){
            int a, b; std::cin >> a >> b;
            c[i] = b - a; sum += a;
        }
 
        std::vector<int> x;
        std::map<int, int> q;
        for(int i = 0; i < n; ++i){
            if(!q.count(c[i])){
                q[c[i]] = 1;
                x.push_back(c[i]);
            }else{
                q[c[i]]++;
            }
        }
        
        std::vector<int> w, v;
        for(int i = 0; i < (int)x.size(); ++i){
            int num = q[x[i]];
            int r = 1;
            while(r <= num){
                w.push_back(x[i] * r);
                v.push_back(r);
                num -= r;
                r <<= 1;
            }
            if(num){
                w.push_back(x[i] * num);
                v.push_back(num);
            }
        }
 
        std::vector<int> dp(m + 1, n + 1); dp[sum] = 0;
        for(int i = 0; i < (int)w.size(); ++i){
            std::vector<int> dpx(dp);
            for(int j = 0; j <= m; ++j){
                if(0 <= j + w[i] && j + w[i] <= m){
                    dpx[j + w[i]] = std::min(dpx[j + w[i]], dp[j] + v[i]);
                }
            }
            dp = dpx;
        }
 
        for(auto xx : dp){
            std::cout << (xx <= n ? xx : -1) << '\n';
        }
    }
 
    return 0;
}

T8:树上背包肯定超时,转移过程用NTT优化,依旧超时。
tip:似乎树上背包可以有一种优化(改造树的形状使其按照某种解法也可以获取答案),这题似乎可以借鉴一下(改造树后,按照类似方法NTT)

标签:std,Atcoder,int,tt,cin,long,++,269
From: https://www.cnblogs.com/iqer/p/16711990.html

相关文章

  • abc269
    \(\textbf{G.}\)设\(c_i=b_i-a_i\),\(S_a=\sum_{i=1}^{n}a_i\).则此时\(k\)的答案为选择最少个数的\(c\)凑出\(k-S_a\)的答案.注意......
  • AtCoder Beginner Contest 258
    AtCoderBeginnerContest258LinkA-When?模拟即可.点击查看代码#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;intmain(){intn;......
  • AtCoder Beginner Contest 269
    比赛链接A模拟即可。点击查看代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;inta,b,c,d;signedmain(){ cin>>a>>b>>c>>d; cout<<(......
  • ABC 269 E - Last Rook(交互题)
    https://atcoder.jp/contests/abc269/tasks/abc269_e有一个N*N的棋盘和N辆车。现在,n-1辆车被放在棋盘上,你必须放置1辆车,满足以下所有条件。没有一行包含两个或更多的车......
  • Atcoder 题集
    Atcoder题集E-Lucky7Battle博弈论,对抗性搜索,记忆化搜索#include<bits/stdc++.h>usingnamespacestd;stringt,x;intn;intf[200010][7];intdfs(inti,intr){......
  • ABC 269 C - Submask(dfs+位运算)
    C-Submask(dfs+位运算)题目大意:给定一个十进制的数字,让我们求出它的二进制下的1可以改变时候的数字SampleInput111SampleOutput10123891011Thebi......
  • AtCoder Regular Contest 148 C Lights Out on Tree
    挺好的一道题,简单写一下题解吧。首先有挺多很naive的结论:每个节点按两遍等于没按。熄灭所有的灯只有一种方案。其实将灯熄灭的方案无非就是从上往下dfs,如果当前灯......
  • AtCoder Beginner Contest 268
    E-ChineseRestaurant(Three-StarVersion)假设旋转\(x\)次时,\(n\)个人失望值的总和为\(c_x\),那么只要能求出\(c_x,0\lex<n\)就可以包含所有情况,然后再取......
  • ABC269
    DContent给你若干个点和相邻点的定义,问你图中有几个连通块。Sol连通用并查集维护,就是这里的相邻有点怪。Code#includeusingnamespacestd;constint_=1005;int......
  • AtCoder Beginner Contest 269 (A-F)题解
    A-AnywayTakahashi这里我还是关了ll的C开了忘了关害的F多了一发罚时#include<bits/stdc++.h>usingnamespacestd;constintN=3e5+10;constintM=9982443......