AtCoder Beginner Contest 412

比赛链接如下:AtCoder Beginner Contest 412 - AtCoder 

5/7 讲解:

A - Task Failed Successfully

Problem Statement

Takahashi set task goals for N days.

He aimed to complete Ai​ tasks on day i(1≤i≤N)i(1≤i≤N), and actually completed Bi tasks.

Find the number of days when he completed more tasks than his goal.

Constraints

  • 1≤N≤100
  • 1≤Ai,Bi≤100
  • All input values are integers.

 解题思路:统计Bi大于Ai的数量

#include<bits/stdc++.h>
using namespace std;
int main(){
  int n; cin>>n;
  int cnt=0;
  for(int i=0;i<n;i++){
    int a,b; cin>>a>>b;
    if(b>a) cnt++;
  }
  cout<<cnt<<endl;
  return 0;
}

 B - Precondition

Problem Statement

You are given strings S and TT consisting of lowercase and uppercase English letters.

Determine whether the string S satisfies the following condition:

  • Every uppercase letter in S that is not at the beginning is immediately preceded by a character contained in T. More formally, for all integers ii such that 2≤i≤∣S∣, if the ii-th character of S is uppercase, then the (i−1)-th character of S is contained in T.

Constraints

  • Each of S and TT is a string consisting of lowercase and uppercase English letters with length between 1 and 100, inclusive.

解题思路:顺次遍历字符串S,若当前字符S[i]是大写, 就查看S[i-1]是否在字符串T中 

#include <bits/stdc++.h>
using namespace std;
int main() {
    string s, t;
    cin >> s >> t;
    set<char> a;
    for (char c : t) a.insert(c);
    for (size_t i = 1; i < s.size(); i++) {
        if (isupper(static_cast<unsigned char>(s[i]))) {
            if (a.find(s[i - 1]) == a.end()) {
                cout << "No" << endl;
                return 0;
            }
        }
    }
    cout << "Yes" << endl;
    return 0;
}

C - Giant Domino 

 

Problem Statement

There are N dominoes numbered from 1 to N. The size of domino ii is Si​.
Consider arranging some dominoes in a line from left to right and then toppling them. When domino i falls to the right, if the size of the domino placed immediately to the right of domino i is at most 2Si​, then that domino also falls to the right.

You decided to choose two or more dominoes and arrange them in a line from left to right. The arrangement of dominoes must satisfy the following conditions:

  • The leftmost domino is domino 1.
  • The rightmost domino is domino N
  • When only domino 11 is toppled to the right, domino N eventually falls to the right as well.

Does an arrangement of dominoes satisfying the conditions exist? If it exists, what is the minimum number of dominoes that need to be arranged?

You are given T test cases, solve the problem for each of them.

Constraints

  • 1≤T≤10^5
  • 2≤N≤2×10^5
  • 1≤Si≤10^9
  • The sum of NN over all test cases is at most 2×10^5
  • All input values are integers.

解题思路:

我们把每个多米诺i看作图中的一个节点,若S[j]<=2*S[i]则从i->j 有一条有向边
由于 N 最多 2*10^5,完全显式存边会爆炸,因此我们把所有未访问的节点放入一个set<pair<size,i>>
每次从队列中取出节点 u,计算 a = 2·S[u],在 set 里一次性"割去"所有 size≤a的节点v,标记它们距离并入队
最后看 dist[n],若仍是-1则不可达,输出-1,否则输出到达n的最小节点数.

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int main(){
  int t; cin>>t;
  while(t--){
    int n; cin>>n;
    vector<ll> s(n+1);
    for(int i=1;i<=n;i++) cin>>s[i];
    vector<int> d(n+1,-1);
    d[1]=1;
    set<pair<ll,int>> st;
    for(int i=2;i<=n;i++) st.insert({s[i],i});
    queue<int> q;
    q.push(1);
    while(!q.empty()){
      int u=q.front(); q.pop();
      ll a=2LL*s[u];
      auto b=st.upper_bound({a,INT_MAX});
      for(auto x=st.begin();x!=b;){
        int v=x->second;
        d[v]=d[u]+1;
        q.push(v);
        x=st.erase(x);
      }
    }
    cout<<d[n]<<endl;
  }
  return 0;
}

 D - Make 2-Regular Graph

Problem Statement

There is a simple undirected graph G with N vertices and M edges. The vertices are numbered 1,2,…,N, and the ii-th edge is an undirected edge connecting vertices Ai​ and Bi​.

You can repeat the following two operations in any order and any number of times:

  • Add one undirected edge to G
  • Remove one undirected edge from G

Find the minimum number of operations to make G a simple undirected graph where all vertices have degree 2.

解题思路:在当前图中添加一条边/删除一条边, 保证图中所有顶点度数均为2的最少操作次数

我们可以枚举:
所有 n! 的排列,代表顶点的遍历顺序。
对于每个排列,用 2^(n-1) 枚举所有「断环点」的位置,即在哪里断开形成多个环(每个环长度 ≥ 3)。
检查该划分是否合法(每个环长度 ≥ 3),并统计这些环中所有的边。
然后比较和原图重叠的边数,设有 cnt 条边在原图中,那么:
要删除 m - cnt 条多余边;
要添加 n - cnt 条缺失边;
总操作数为:(m - cnt) + (n - cnt) = m + n - 2 * cnt
我们要取最小操作数。

#include<bits/stdc++.h>
using namespace std;
using pii=pair<int,int>;
set<pii> g;
int n,m; 
int solve(){
    vector<int> p(n);
    iota(p.begin(),p.end(),0);
    int ans=INT_MAX;
    do{
        for(int m=0;m<(1<<(n-1));m++){
            vector<vector<int>> c;
            vector<int> cur;
            bool f=true;
            for(int i=0;i<n;i++){
                cur.push_back(p[i]);
                if(i==n-1||(m&(1<<i))){
                    if(cur.size()<3){
                        f=false;
                        break;
                    }
                    c.push_back(cur); cur.clear();
                }
            }
            if(!f) continue;
            set<pii> ne;
            for(auto& x:c){
                int n=x.size();
                for(int i=0;i<n;i++){
                    int u=x[i],v=x[(i+1)%n];
                    if(u>v) swap(u,v);
                    ne.insert({u,v});
                }
            }
            int cnt=0;
            for(auto& [u,v]:ne){
                if(g.count({u,v})) cnt++;
            }
            int ct=g.size()+ne.size()-2*cnt;
            ans=min(ans,ct);
        }
    }while(next_permutation(p.begin(),p.end()));
    return ans;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int u,v;
        cin>>u>>v;
        u--; v--;
        if(u>v) swap(u,v);
        g.insert({u,v});
    }
    cout<<solve()<<endl;
    return 0;
}

E - LCM Sequence

Problem Statement

For a positive integer nn, define An​ as the least common multiple of 1,2,…,n.
You are given positive integers L and R. How many distinct integers are contained in the sequence (AL,AL+1,…,AR)?

Constraints

  • 1≤L≤R≤10^14
  • R−L≤10^7
  • L and R are integers.

解题思路:An表示1,2...n的最小公倍数, 求L...R的中不同数的个数

An​ 是一个单调不减的数列。

An 的值会变化(即 An​>An−1​)当且仅当 n 引入了新的质因子或新的质数的高次幂。

情况 1:n 是素数。

因为 n 是新的素数,之前 An−1​ 中不包含 n,所以 An​=An−1​×n。

情况 2:n 是某个素数 p 的高次幂(即 n=p^k, k≥2)。

此时 An−1 中已经包含 p,但可能不包含 pk 的足够高次幂。

例如:A4​=12=LCM(1,2,3,4)。

4=2^2,而 A3=6=2×3 中 2 的最高次幂是 2。

因此 A4=12=2^2×3,比 A3​ 多了一个 2 的因子。

其他情况(n 是合数但不是质数的高次幂):
An​ 不会变化,因为 n 的所有质因子已经在 An−1​ 中以足够高的幂次出现。

例如:A6=LCM(1,2,3,4,5,6)=60=A5​(因为 6 = 2 × 3,而 2 和 3 已经在 A5​ 中)。

问题转化
根据上述分析:
序列 (AL,AL+1,…,AR) 中不同的值的数量, 等于 An​ 在 n∈[L,R] 中发生变化的次数加 1(初始的 AL​)。
An的变化次数=区间(L,R]内素数的数量+区间(L,R]内质数高次幂的数量。
因此:
统计区间(L,R]内的素数数量cnt1。
统计区间(L,R]内的质数高次幂数量 cnt2。
最终答案=1 + cnt1 + cnt2。

 

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll count_primes(ll l, ll r) {
    ll a = sqrt(r);
    vector<char> m(a + 1, true);
    if (a >= 1) m[0] = m[1] = false;
    vector<int> primes;
    for (ll i = 2; i <= a; i++) {
        if (m[i]) {
            primes.push_back(i);
            for (ll j = i * i; j <= a; j += i) {
                m[j] = false;
            }
        }
    }
    ll s = r - l + 1;
    vector<char> is_prime(s, true);
    if (l == 1) is_prime[0] = false;
    for (ll x : primes) {
        ll st = max(x * x, ((l + x - 1) / x) * x);
        for (ll y = st; y <= r; y += x) {
            is_prime[y - l] = false;
        }
    }
    return count(is_prime.begin(), is_prime.end(), true);
}

int main() {
    ll l, r;
    cin >> l >> r;
    ll prime_cnt = count_primes(l + 1, r);
    ll a = sqrt(r);
    vector<char> m(a + 1, true);
    if (a >= 1) m[0] = m[1] = false;
    vector<int> primes;
    for (ll i = 2; i <= a; i++) {
        if (m[i]) {
            primes.push_back(i);
            for (ll j = i * i; j <= a; j += i) {
                m[j] = false;
            }
        }
    }
    ll tot_cnt = 0;
    for (int pr : primes) {
        ll x = (ll)pr * pr;
        while (x <= r) {
            if (x > l) ++tot_cnt;
            if (x > r / pr) break; 
            x *= pr;
        }
    }
    cout << (1 + prime_cnt + tot_cnt) << endl;
    return 0;
}

感谢大家的点赞和关注,你们的支持是我创作的动力!

吐槽:感觉最近异常倒霉啊...

 

AtCoder Beginner Contest 412AtCoder 平台举办的面向初学者的编程比赛之一。以下是与该比赛相关的信息及部分题解内容: ### 比赛信息 - **比赛时间**:通常为北京时间周六或周日上午,具体时间需参考官方公告。 - **参赛对象**:适合所有编程水平的选手,尤其是初学者。 - **题目数量**:一般包含 8 道题目(A-H),难度从简单到中等递增。 - **评分规则**:采用 ICPC 规则,根据通过的测试点数量进行评分。 ### 题目特点 - **A - E 题**:基础模拟、数学运算、字符串处理等常见类型问题。 - **F - H 题**:涉及图论、动态规划、贪心算法等较复杂算法应用。 ### 解题思路示例 以下为部分题目可能涉及的解题思路: - **A题**:判断输入是否满足特定条件,例如数值范围、奇偶性等。 - **B题**:简单的字符串操作,如查找重复字符或计算特定字符数量。 - **C题**:使用数组或结构体进行数据存储和遍历,可能涉及排序或查找。 - **D题**:数学建模,例如求最小公倍数、最大公约数等。 - **E题**:基本的贪心策略,例如选择最优路径或最少操作次数。 - **F题**:图论中的最短路径问题,可能使用 BFS 或 Dijkstra 算法。 - **G题**:动态规划,需要构建状态转移方程解决计数问题。 - **H题**:较为复杂的综合应用,可能涉及组合数学或高级数据结构。 ### 示例代码 以下为一道典型问题的解法代码片段: ```cpp #include <bits/stdc++.h> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; ++i) { cin >> a[i]; } sort(a.begin(), a.end()); cout << a[k - 1] << endl; return 0; } ``` ### 常见错误提醒 - **边界条件**:注意输入值为 0 或最大值的情况。 - **数据类型**:避免整数溢出,使用 `long long` 类型处理大数。 - **输入输出格式**:严格遵循题目要求,包括空格、换行符等。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值