假设两个操作者分别为$A$和$B$,其中$A$希望最大、$B$希望最小
(并不默认$A$为整局游戏的先手,仅是最终的结果考虑$A$为先手时)
记第$i$个队列第$j$个元素为$a_{i,j}$(其中$1le ile k,1le jle n_{i}$)
特判$n_{i}=1$的队列,直接把队列中的元素加到最后的和中即可
当$k=1$时且$A$为先手时,答案为(为了方便,均省略$n_{1}$和$a_{1,i}$中的1)
$$
egin{cases}max(a_{frac{n}{2}},a_{frac{n}{2}+1})&(nequiv 0(mod 2))\min(a_{frac{n+1}{2}},max(a_{frac{n-1}{2}},a_{frac{n+3}{2}}))&(nequiv 1(mod 2))end{cases}
$$
若$B$为先手,将$max$和$min$交换(改为另一种)即可
(正确性把所有情况一起按照$n$归纳即可)
下面,考虑若$A$可以选择哪一方为先手,此时$A$会选择谁(仍在$k=1$的基础上)
对两种情况分别讨论,不难得到$A$会在$nequiv 0(mod 2)$时选择$A$,$nequiv 1(mod 2)$时选择$B$
同理,$B$会在$nequiv 0(mod 2)$时选择$B$,$nequiv 1(mod 2)$时选择$A$
通俗的来说,即序列长度为偶数时双方会去操作,而奇数时双方希望对方先操作
(关于这个结论,仅仅是方便思考,并不能证明下面做法的正确性)
由此,当所有序列长度都为奇数,显然当先手操作某一个序列,后手都跟着操作即可,独立求出每一个序列的$A$为先手的答案并求和即可
对于长度为偶数的序列,双方的策略即先手选择一个长度为偶数的序列,后手选择另一个长度为偶数的序列,不断选择直至没有偶数的序列,最后根据奇偶性即可判定谁先选长度为奇数的序列
关于选择哪一个,显然按照两种情况的差值排序后贪心选择即可
总复杂度为$o(klog k)$,可以通过
(正确性把所有情况一起按照$sum_{i=1}^{k}n_{i}$归纳即可)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 vector<int>v,a[N]; 5 int n,x,s,m[N]; 6 long long ans; 7 int main(){ 8 scanf("%d",&n); 9 for(int i=1;i<=n;i++){ 10 scanf("%d",&m[i]); 11 if (m[i]==1){ 12 scanf("%d",&x); 13 ans+=x; 14 i--,n--; 15 continue; 16 } 17 for(int j=1;j<=m[i];j++){ 18 scanf("%d",&x); 19 a[i].push_back(x); 20 } 21 if (m[i]%2==0)s++; 22 } 23 if (s%2==0){ 24 for(int i=1;i<=n;i++){ 25 if (m[i]&1)ans+=min(a[i][m[i]/2],max(a[i][m[i]/2-1],a[i][m[i]/2+1])); 26 else{ 27 int x=a[i][m[i]/2-1],y=a[i][m[i]/2];//最中间两个 28 ans+=min(x,y); 29 if (m[i]==2)v.push_back(abs(x-y)); 30 else v.push_back(max(min(x,max(a[i][m[i]/2-2],y)),min(y,max(x,a[i][m[i]/2+1])))-min(x,y)); 31 } 32 } 33 sort(v.begin(),v.end()); 34 for(int i=1;i<s;i+=2)ans+=v[i]; 35 printf("%lld",ans); 36 return 0; 37 } 38 for(int i=1;i<=n;i++){ 39 if (m[i]&1)ans+=max(a[i][m[i]/2],min(a[i][m[i]/2-1],a[i][m[i]/2+1])); 40 else{ 41 int x=a[i][m[i]/2-1],y=a[i][m[i]/2]; 42 ans+=max(x,y); 43 if (m[i]==2)v.push_back(-abs(x-y)); 44 else v.push_back(min(max(x,min(a[i][m[i]/2-2],y)),max(y,min(x,a[i][m[i]/2+1])))-max(x,y)); 45 } 46 } 47 sort(v.begin(),v.end()); 48 for(int i=1;i<s;i+=2)ans+=v[i]; 49 printf("%lld",ans); 50 }