题目大意:
总共有n个人和n个数字
n个人拍成一队,n个数字也是有顺序的
你排在第m个位置
按照顺序的每个人可以拿走这个序列中的第一个数字或者最后一个数字
你可以在所有人操作开始前说服最多k个人
让他们固定拿这个序列的第一个或者是最后一个数字
问你在所有可能的情况中可以拿到的数字的最大值中的最小值(即,到你取得的时候,首尾两个数字你总是会取最大的那个,问这些数字中的最小值)
※所有没有被说服的人拿数字是随机拿的,不存在博弈论中的什么总是拿最大或最小
解题思路:
因为只有说服排在自己前面的人才有用
所以可以先让 k=min(k,m-1)
每次轮到自己时,场上还会剩下n-m+1个数字,所以先令len=n-m+1
每次在自己前面的人里至少会有m-k-1个人是不受控制的,令rand=m-k-1
先预处理出最后可能的答案所在区间的答案
即取一段长度为len的区间,答案即它的左端点与右端点中的较大值
总共会有n-len+1个区间,即m个区间,将答案存在数组dm中待调用
然后,最多可以说服k个人,贪心可得越多人能被说服则对答案贡献更大
又因为除了这些被说服的人外,其他排在自己前面的人没被说服的(随机的)人的操作方式是不可预判的!!!
所以,这些被说服的人最好能先取,才能让整个局面更能被自己掌握(确信嘿嘿嘿)
综上,就可以开始枚举这k个人里,有多少人取了这个数列的前端,有多少人取了后端
则循环 i=0~k,i 表示有i个人取了前端
那么,这样取的话最后答案区间就会变成 [i+1,n-i] ,总共会出现rand+1个len长度的可能答案
又因为前面预处理了最后可能的答案
所以最终再循环一次 j=i+1~i+1+rand
取这些答案中的最小值mn
所以这就是这一遍的答案
又因为说服的那些人怎么操作是可控的
所以最终的答案是所有mn中的最大值!!!
(暴力吧,很快的)
1 #include2 using namespace std; 3 int ar[3550],dm[3550]; 4 void solve(){ 5 int n,m,k,len,rand,i,j,ans=0,mn; 6 cin>>n>>m>>k; 7 k=min(k,m-1); 8 len=n-m+1; 9 rand=m-k-1; 10 for(i=1;i<=n;i++){ 11 cin>>ar[i]; 12 if(i>=len) 13 dm[i-len+1]=max(ar[i],ar[i-len+1]); 14 } 15 for(i=0;i<=k;i++){ 16 mn=0x3f3f3f3f; 17 for(j=i+1;j<=i+1+rand;j++) 18 mn=min(mn,dm[j]); 19 ans=max(ans,mn); 20 } 21 cout< '\n'; 22 } 23 int main(){ 24 ios::sync_with_stdio(0); 25 cin.tie(0);cout.tie(0); 26 int T;cin>>T;while(T--) 27 solve(); 28 29 return 0; 30 }