题目描述
小明喜欢玩飞镖游戏,他会把每次的得分都记录在数组中。今天有个飞镖大奖,得奖的规则是:如果你 4 次飞镖的得分先后是(a,b,c,d),满足 abc = d 。
小明准备把记录里的其他项删除,只留下满足获奖条件的 4 个分数,他想问你有多少种不同方案?
题解
对于这种题容易想到开桶,因为和顺序有关所以我们可以枚举一条分界线,比如在b,c中间划一刀,前面的a*b,后面的d/c一定能拿到所以双指针扫过去,注意先统计答案,不要自己更新自己了
代码
#include <bits/stdc++.h>
#define maxn 1000005
#define LL long long
using namespace std;
int read(){
int res; bool f=1; char c;
while(!isdigit(c=getchar())) if(c=='-') f=0; res=(c^48);
while(isdigit(c=getchar())) res=(res<<3)+(res<<1)+(c^48);
return f?res:-res;
}
int n,a[maxn],tax[maxn],mx;
LL ans;
int main(){
n=read();
for(int i=1;i<=n;i++) mx=max(mx,a[i]=read());
for(int i=1;i<=n;i++){
for(int j=n;j>i;j--)if(a[j]%a[i]==0){
ans+=tax[a[j]/a[i]];
}
for(int j=1;j<i;j++)if(1ll*a[j]*a[i]<=mx){
tax[a[j]*a[i]]++;
}
}
printf("%lld",ans);
return 0;
}
题解2
有一种更显然但是带Log的方法,我们先暴力出vector存下每个c/d出现的位置,然后再暴力地枚举a和b,在b之后的位置lower_bound即可
代码2
#include <bits/stdc++.h>
using namespace std;
int n,a[2005],ax;long long ans;
vector<int>p[1000005];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),ax=max(a[i],ax);
for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++)
if (1ll*a[i]*a[j]<=ax) p[a[i]*a[j]].push_back(j);
for (int i=1;i<=ax;i++) sort(p[i].begin(),p[i].end());
for (int i=n;i;i--) for (int j=i-1;j;j--)
if (a[i]%a[j]==0) ans+=upper_bound(p[a[i]/a[j]].begin(),p[a[i]/a[j]].end(),j-1)-p[a[i]/a[j]].begin();
return printf("%lld\n",ans),0;
}