atcoder 439D

题目大意

(https://atcoder.jp/contests/abc439/tasks/abc439_d)
给你一个数组,要求求出满足要求的(Ai,Aj,Ak)要求是
三个数字之比是7:5:3
这三个数字中j不可以是中间那个数字,要么是最大,要么是最小

分析

直接去算的话,未免有点困难,所谓正难则反,我们可以先把所有的都求出来,然后减去不满足要求的,剩下的就是我们要的

1.核心函数

int cal(vector<int>&v7,vector<int>&v5,vector<int>&v3){
    int res=v7.size();
    res*=v5.size();
    res*=v3.size();
    vector<pair<int,int>>vp;
    for(auto&nx:v7)vp.pb({nx,7});
    for(auto&nx:v5)vp.pb({nx,5});
    for(auto&nx:v3)vp.pb({nx,3});
    sort(all(vp));
    int l7=0,r7=v7.size();
    int l3=0,r3=v3.size();
    for(int i=0;i<vp.size();i++){
        if(vp[i].second==5){
            res-=l7*r3;
            res-=l3*r7;
        }else if(vp[i].second==3){
            l3++;
            r3--;  
        }else if(vp[i].second==7){
            l7++;
            r7--;
        }
    }
    return res;
}

就是把以x为基地(7x,5x,3x)的所有可能乘起来这个就是总的,然后按照下标给这些排序,然后计算出在以x为基底的的情况下,有多少事j为中间那个数字的情况,也就是5在中间,7在头3在尾巴,和3在头7在尾
把这些减去就好了

完整code

#include<bits/stdc++.h>
using namespace std;
//"O campeão tem nome, e se chama Charles Oliveira!"
#define int long long
#define endl '\n'
#define ep emplace
#define pob 
#define ll long long
#define pb push_back
#define pof pop_front
#define pob pop_back
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define mod 998244353
#define MOD 1000000007
const int N=200005;

using ld = long double;
using ui = unsigned;
using ull = unsigned long long;
using i128 = __int128;

int fastpow(int x,int y){
    int temp=1;
    while(y){
        if(y&1)temp*=x;
        x*=x;
        y>>=1;
    }
    return temp;
}
int cal(vector<int>&v7,vector<int>&v5,vector<int>&v3){
    int res=v7.size();
    res*=v5.size();
    res*=v3.size()
    vector<pair<int,int>>vp;
    for(auto&nx:v7)vp.pb({nx,7});
    for(auto&nx:v5)vp.pb({nx,5});
    for(auto&nx:v3)vp.pb({nx,3});
    sort(all(vp));
    int l7=0,r7=v7.size();
    int l3=0,r3=v3.size();
    for(int i=0;i<vp.size();i++){
        if(vp[i].second==5){
            res-=l7*r3;
            res-=l3*r7;
        }else if(vp[i].second==3){
            l3++;
            r3--;
        }else if(vp[i].second==7){
            l7++;
            r7--;
        }
    }
    return res;
}
void solve(){
    int N;cin>>N;
    vector<int>a(N+1);
    map<pair<int,int>,vector<int>>mp;
    set<int>s;
    for(int i=1;i<=N;i++){
        cin>>a[i];
        if(a[i]%7==0){
            mp[{a[i]/7,7}].pb(i);
            s.insert(a[i]/7);
        }
        if(a[i]%3==0)mp[{a[i]/3,3}].pb(i);
        if(a[i]%5==0)mp[{a[i]/5,5}].pb(i);
    }
    int res=0;
    for(auto&i:s){
        res+=cal(mp[{i,7}],mp[{i,5}],mp[{i,3}]);
    }
    cout<<res<<endl;
}

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

小疑惑

if(a[i]%7==0){
            mp[{a[i]/7,7}].pb(i);
            s.insert(a[i]/7);
        }

这个的set里存的是什么呢?其实就是上面说的基地,把这个数组中所有基底的情况都考虑一遍,每个基底都按照上面那个方法计算一次,再把总的加起来,就是我们想要的答案了
为什么存的是除以7的?为什么不是除以5或者除以3呢,其实都是一样的,因为,如果一个基底7在这个数组中是找不到的话,那就没必要去计算了
那要是这个基底x
7在数组中有,但是它乘以5或者3在数组中没有呢?我们在计算的时候,就是

int res=v7.size();
    res*=v5.size();
    res*=v3.size();

如果有一个没有的话,乘的就是0,那么也就不用担心会影响我我们答案的结果了

posted @ 2026-03-27 23:55  Time_q  阅读(4)  评论(0)    收藏  举报