思路
例如[1 2 2 1]数组,长度为3的数组为[1 2 2] 和 [2 2 1],有此例子可以知道,两个区间必有2个元素是一样的,要使所有长度为3的区间和相等,那么两个区间里面的元素必定要相同,即第i个元素的值要等于第i+k个元素的值,才是k-好数组。
先来引入什么是下标余数:
当我们想要访问数组中的元素时,通常会使用下标来定位。在某些情况下,我们可能需要通过某种计算来确定一个元素的位置,这时就可以使用取余运算来确保得到的下标不会超出数组的界限。例如,如果有一个长度为10的数组,当我们尝试访问第13个元素时,可以使用13除以10的余数来确定该元素的下标,即13 % 10
结果为3,这样就可以通过arr[3]
来访问第13个元素而不会出现越界错误。
下标余数:0 1 2 0
数组: 1 2 2 1
每一组len = k 的元素下标:
0 1 2
1 2 0
可以知道余数相同的值要一样才能是好数组
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
int n,k,x;
vector<int> tr[N]; //用来存i%k的值,即i,i+k……等的值
void solve(){
cin>>n>>k>>x;
for(int i=0;i<k;i++) tr[i].clear(); //初始化
for(int i=0;i<n;i++){
cin>>a[i];
tr[i%k].push_back(a[i]); //每一组存的是a[i],a[i+k]……等等
}
int cnt=0;
for(int i=0;i<k;i++){
sort(tr[i].begin(),tr[i].end()); //排序
for(int v:tr[i]){ //全部变成最大的那个值需要操作的次数
cnt+=tr[i].back()-v; //因为每次操作只能加,所以最终每组的数都会变成最大的那个数
}
}
x-=cnt; //总操作减去上面操作的次数
if(x<0){ //小于0则无法变成好数组
cout<<-1<<'\n';
return ;
}
int ans=0;
for(int i=0;i<k;i++){ //找剩余操作数操作完后的最大数
ans=max(ans,tr[i].back());
int len=tr[i].size();
ans=max(ans,(int)tr[i].back()+x/len); //x/len是因为每个数都要同时加
}
cout<<ans<<'\n';
}
signed main(){
int t;
cin>>t;
while(t--) solve();
}