/*刚开始的思路是直接搜索暴力,很显然wa了,时间超限只过了20%(可能剩下的80%要求优化啥的,编者没有想到,但感觉应该不没啥优化的点了,可能这个题目本来的方法就不是搜索吧)*/
后面看了别人的题解才有所感悟,其实处理方法不久前才接触过
1.三个数的和对k取余结果是0,可见这三个数对k取余的和对k取余是0。( (a+b+c)%k==(a%k+b%k+c%k)%k )
2.可以排序后利用二维栈将余数相同的数按照从小到打的顺序存储(那么在出栈的时候就是从大到小了)
3.因为题目只需要求三个数,二重循环+判断就可以选出最大的和了
这个是之前没有AC的深搜写法,时间超限,只过了20%(如果有大佬可以有优化方案,评论区告诉一下,谢谢了)
#include<bits/stdc++.h>
using namespace std;
int num[100005];
int vis[100005];
int n,k,ans;
inline void dfs(int st,int sum,int cn){
if(cn>3){
if(sum%k==0){
ans=max(ans,sum);
return ;
} else {
return ;
}
}
for(int i=st;i<=n;i++){
if(!vis[i]){
vis[i]=1;
dfs(i,sum+num[i],cn+1);
vis[i]=0;//利用回溯
}
}
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
}
sort(num+1,num+1+n,greater<int>());
dfs(1,0,1);
cout<<ans<<endl;
return 0;
}
这个是利用二维栈来解决(博主认为只是寻找3个数,可以使用,要是要选的数多了,这个方法是不是可以要打一个问号了,但是这个方法确实是一个不错的方法)
#include<bits/stdc++.h>
using namespace std;
int a[100005];
stack<int>num[1005];
int n,k;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
num[a[i]%k].push(a[i]);//利用二维栈来存储余数相同的数,并且是从小到大(出栈的时候就是从大到小)
}
int res=0;
for(int i=0;i<k;i++){
if(num[i].empty()){
continue;//如果第一个余数已经没有了,那么将跳过这个余数
}
for(int j=0;j<k;j++){
if(num[j].empty()){
continue;//如果第二个余数没有了,那么将直接跳过这个余数
}
int rm=(k-i-j+k)%k;//找到第三个数应该的余数
int tmp=0,ans1,ans2,ans3;
if(rm<j){
continue;
}
if(num[i].size()){
ans1=num[i].top();
tmp+=ans1;
num[i].pop();
if(num[j].size()){
ans2=num[j].top();
tmp+=ans2;
num[j].pop();
if(num[rm].size()){
ans3=num[rm].top();
tmp+=ans3;
num[rm].pop();
res=max(res,tmp);
num[rm].push(ans3);
}
num[j].push(ans2);
}
}
num[i].push(ans1);
}
}
cout<<res<<endl;
return 0;
}
/*总结:利用下表存余数或者其他数,这种方法是本题目的一个核心之一了*/
由于发布的时间太晚了,还有一个类似的题目来不及写,希望大家可以后续关注,一键三连哦.(补博客链接:https://blog.csdn.net/qq_46037076/article/details/115322537)
20岁的年纪不应该选择脱单,应该选择脱贫。