Loading

【题解】Atcoder Beginner Contest 439(ABC439) A~E

A - 2^n - 2*n

直接计算即可。

#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;
    cout<<pow(2,n)-2*n;
    return 0;
}

B - Happy Number

直接模拟即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,t;
bool vis[N];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;
    t=n;
    while(t!=1){
        int tmp=t,sum=0;
        while(tmp){
            sum+=((tmp%10)*(tmp%10));
            tmp/=10;
        }
        t=sum;
        if(t==1){
            cout<<"Yes";
            return 0;
        } 
        if(vis[t]){
            cout<<"No";
            return 0;
        }
        vis[t]=1;
    }
    cout<<"Yes";
    return 0;
}

C - 2026

因为 \(n\le 10^7\),所以 \(x,y\le \sqrt{10^7}\),两层循环枚举 \(x,y\),将 \(x^2+y^2\) 的解数 \(+1\),最后枚举统计解为 \(1\) 的数输出。时间复杂度 \(O(n)\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int n,ans;
int cnt[N];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n/i;i++){
        for(int j=i+1;j<=n/j;j++){
            long long sum;
            sum=1ll*(1ll*i*i+1ll*j*j);
            if(sum<=n) cnt[sum]++; 
        }
    }
    for(int i=1;i<=n;i++){
        if(cnt[i]==1) ans++;
    }
    cout<<ans<<'\n';
    for(int i=1;i<=n;i++){
        if(cnt[i]==1) cout<<i<<' ';;
    } 
    return 0;
}

D - Kadomatsu Subsequence

注意到第三个条件,\(j\) 只能为三元组中在原数组里第一个或最后一个出现的元素。这是一个很好的性质,启发我们可以用前缀后缀的思想来求解。

接着考虑剩下两个元素,注意到剩下两个元素都唯一确定,所以开一个 map 维护每个元素在此之前出现的数量,\(A_i=A_j\div 5 \times 3, A_k=A_j\div 5 \times 7\)。使用乘法原理,二元组数量为两者数量之积,累加计入答案。

这是 \(j\) 作最后一个出现的元素时的情况,反着求一遍就是另一种情况。

时间复杂度 \(O(n)\)

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n;
long long ans;
int a[N];
map<int,int> mp3,mp7;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i]%3==0) mp3[a[i]/3]++;
        if(a[i]%7==0) mp7[a[i]/7]++;
        if(a[i]%5==0) ans+=1ll*(1ll*mp3[a[i]/5]*1ll*mp7[a[i]/5]);
    }
    mp3.clear();
    mp7.clear();
    for(int i=n;i>=1;i--){
        if(a[i]%3==0) mp3[a[i]/3]++;
        if(a[i]%7==0) mp7[a[i]/7]++;
        if(a[i]%5==0) ans+=1ll*(1ll*mp3[a[i]/5]*1ll*mp7[a[i]/5]);
    }
    cout<<ans;
    return 0;
}

E - Kite

将线段交叉转化,即可得到合法的两条线段为:

  • \(A_i<A_j,B_i<B_j\)
  • \(A_i>A_j,B_i>B_j\)

想到按 \(A_i\) 大小升序排序,此时题目转化为了求当前 \(B_i\) 的最长上升子序列。

使用二分优化 LIS 求解。时间复杂度 \(O(n\log n)\)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
struct Node{
    int a,b;
}kt[N];
int n,len;
int f[N];
bool cmp(Node x,Node y){
    if(x.a==y.a) return x.b>y.b;//为了防止两个线段在 a 处有交点,直接将 a 相同的点的 b 降序排序,保证不影响答案。但其依然可以接在 a 不相同的点后面构成上升子序列,所以不能跳过。
    return x.a<y.a;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>kt[i].a>>kt[i].b;
    sort(kt+1,kt+1+n,cmp);
    for(int i=1;i<=n;i++){
        if(kt[i].b>f[len]) f[++len]=kt[i].b;
        else{
            int t=lower_bound(f+1,f+1+len,kt[i].b)-f;
            f[t]=kt[i].b;
        }
    }
    cout<<len;
    return 0;
}
posted @ 2026-01-03 22:45  Seqfrel  阅读(122)  评论(0)    收藏  举报