题目链接

https://codeforces.com/contest/1399/problem/C

解题思路

暴力枚举。
先枚举所有可能的和,再枚举左加数,通过和与左加数求出右加数,统计满足的对数。
最后遍历一遍所有可能的和,找到对数最多的,即为答案。

AC代码

#include<bits/stdc++.h>
#define ll long long

using namespace std;

const int N=110;//一定要开够啊!!我心态崩了
int a[N],cnt[N],mx,n,T,ans[N],res;//cnt[i]用来记录数值为i的数量,ans[i]记录和为i的对数的两倍(暂时明白i表示和就行),mx是数组a中最大的数

int main()
{
    cin>>T;
    while(T--)
    {
        mx=0;res=0;
        memset(cnt,0,sizeof cnt);
        memset(ans,0,sizeof ans);
        cin>>n;
        for(int i=1;i<=n;i++)
        cin>>a[i],mx=max(mx,a[i]),cnt[a[i]]++;//统计每种数的数量    

        for(int i=2;i<=(mx<<1);i++)//遍历所有和的可能,最大为mx*2吧
        for(int j=1;j<i;j++)//枚举左加数,通过左加数求出右加数。具体而言就是,我们枚举和为i,再枚举左加数j,那么要让j+某数=i,那么,某数一定为i-j。
        ans[i]+=min(cnt[i-j],cnt[j]);//短板效应,i-j这个数与j这个数匹配成i的最多数量肯定是二者中数量少的决定。

        for(int i=2;i<=(mx<<1);i++)//再遍历所有的和,找到对数最多的。
        //注意/2,比如当上面的循环i=5,j=1时,ans+=min(cnt[4],cnt[1]),而j枚举到4的时候,ans+=min(cnt[1],cnt[4]),cnt[1]与cnt[4]的大小关系是不变的,所以相当于加了两遍。
        //同时我们还应注意考虑一下特殊情况,比如2,2,2,2,2匹配的时候,不同的i,j=2的情况只枚举一次,因此cnt[2]只会被加一次,最后会/2,所以通过2与2配对的贡献为5/2=2,是正确的配对数,没问题
        res=max(ans[i]/2,res);


        cout<<res<<endl;    
    }     
}