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在这个数组中是找不到的话,那就没必要去计算了
那要是这个基底x7在数组中有,但是它乘以5或者3在数组中没有呢?我们在计算的时候,就是
int res=v7.size();
res*=v5.size();
res*=v3.size();
如果有一个没有的话,乘的就是0,那么也就不用担心会影响我我们答案的结果了

浙公网安备 33010602011771号