Managing Difficulties(mp的变形+三元组)

Every day a new programming problem is published on Codehorses. Thus, n problems will be published in the following n days: the difficulty of the i-th problem is ai.
Polycarp wants to choose exactly three days i, j and k (i < j < k) so that the difference of difficulties on the day j and the day i is equal to the difference of difficulties on the day k and day j. In other words,Polycarp wants equality aj − ai = ak − aj to be true.
Determine the number of possible ways for Polycarp to choose the three days in the desired way.

输入

The first line contains an integer t — the number of test cases in the input (1 ≤ t ≤ 10). Then t test case descriptions follow.
The first line of a test case contains an integer n — the number of the days (3 ≤ n ≤ 2000).
The second line of the test case contains n integers a1, a2, ... , an, where ai is the difficulty of the problem on the i-th day (1 ≤ ai ≤ 109).

输出

Output t integers — the answers for each of the test cases in the input, in the order they are given. The answer to a test case is the number of triples of indices i, j, and k such that 1 ≤ i < j < k ≤ n and
ak − aj = aj − ai. 

样例输入 Copy

4
5
1 2 1 2 1
3
30 20 10
5
1 2 2 3 4
9
3 1 4 1 5 9 2 6 5

样例输出 Copy

1
1
4
5

题目的意思就是让你找一个三元组i,j,k,使得ak − aj = aj − ai.暴力肯定要超时,显然要对式子变形。 

1.一开始是做的时候我们做的时候就是变成2*a[j]=a[k]+a[i]就是枚举a[k]和a[i]。用一个前缀和的思想预处理出来a[k]到a[i]的
中a[j]的个数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
unordered_map<ll,ll> mp;
inline ll read(){
    ll  x=0;
    bool f=0;
    char ch=getchar();
    while (ch<'0'||'9'<ch)    f|=ch=='-', ch=getchar();
    while ('0'<=ch && ch<='9')
        x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
ll a[2010],f[2010][2010];
int main()
{
    ll t;
    t=read();
    while(t--)
    {
        memset(a,0,sizeof a);
        int n;
        n=read();
        int s = 0;
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            if(!mp[a[i]]) mp[a[i]]=++s;
        }
        memset(f,0,sizeof f); 
        for(int i=1;i<=s;i++)
        {
            for(int j=1;j<=n;j++)
            {
                //f[i][j]表示前j项中有多少个i
                if(mp[a[j]]==i) f[i][j]=f[i][j-1]+1;
                else f[i][j]=f[i][j-1];
            }
        }
        ll ans=0;
        for(int i=1;i<=n-2;i++)
        {
            for(int k=i+2;k<=n;k++)
            {
                ll tmp=a[i]+a[k];
                if(tmp%2!=0) continue;
                ll val=tmp/2;
                ll idx=mp[val];
                ll num=f[idx][k-1]-f[idx][i];
                ans+=num;
            }
        }
        printf("%lld\n",ans);
        mp.clear();
    }
    return 0;
 }

2.正解就是让a[i]=2*a[j]-a[k],就一个map就解决了,太妙了

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstring>
#include<map>
#include<cstdio>
#include<iostream>
#include<queue> 
#include<algorithm>
using namespace std;
typedef long long ll;
template <typename Tp>
void read(Tp &x){//read(n);
    x=0;char ch=1;int fh;
    while(ch!='-'&&(ch>'9'||ch<'0')){
        ch=getchar();
    }
    if(ch=='-'){
        fh=-1;ch=getchar();
    }else fh=1;
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+ch-'0';ch=getchar();
    }
    x*=fh;
}
inline char read1()//字符串读入挂
{
    register char ch=getchar();
    while(ch<'A'||ch>'M')ch=getchar();
    return ch; 
}
const int maxn=1e6+100;
const int mod=1000000007;
int a[maxn];
map<int,int>mp;
int main()
{
    ll t;
    read(t);
    while(t--){
        mp.clear(); 
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        mp[a[1]]=1;
        int ans=0;
        for(int j=2;j<=n;j++){
            for(int k=j+1;k<=n;k++){
                int temp=2*a[j]-a[k];
                if(temp<0||mp[temp]==0){
                    continue;
                }
                ans+=mp[temp];
            }
            mp[a[j]]++;//这样就能找出j之前的a[i]的个数 
        } 
        cout<<ans<<endl;
    }
    return 0;
 }

 



posted @ 2020-10-11 09:40  哎呦哎(iui)  阅读(269)  评论(0编辑  收藏  举报