题目链接
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; } }