今晚做了两道题。
第一道第一部分思路是对的,但是第二部分出了岔子。两部分问题相似,我以为是跟第一部分的处理方式相似,就一直在凑,导致WA了好久。
第二道题的思路是对的,但是我代码不够简洁,导致bug很多,一直打补丁。
今日总结:注意减少惯性思维,AC完也要找题解去学习,WA后注意减少打补丁的行为。
C. Min-Max Array Transformation
题目大意: 有三个数组 A, B, D。Bi = Ai + Di。B数组第i个元素是由A和D的第i个元素相加所得。现在已知 非递减的数组A和数组B。让求 满足条件的D的每个最小元素和最大元素。( Ai + Di 后得到的Bi数组可以进行乱序或排序)
(均为非负数)
思路: 因为B是由A和D的第i个元素相加得到的,并且A和B是非递减的。每个di*min 是满足在B all中第一个大于等于A中第i的元素的元素与Ai的差。
对于求最大的Di max来说,当A中有后面元素大于B中元素的时候,会让Di max的值减小。这是由于Di和Ai之和大于某B时,一定有一个Aj (j > i) 是不能与一个Bi匹配的。
因此可以从后往前遍历,找第一个大于等于Ai的Bj元素,令t为查找到的元素在B中的下标。当t 等于 i时,表示这是A<t元素的最大值的分界。
const int N = 200021;
int a[N], b[N];
int ans[N][2];
void solve() {
int n; cin>>n; rep(i,1,n) scanf("%d", &a[i]); rep(i,1,n) scanf("%d", &b[i]);
int top = n; // 约束值
for(int i = n; i >= 1; --i) {
int t = lower_bound(b+1, b+n+1, a[i]) - b;
if(t == i) {
ans[i][0] = b[i] - a[i];
ans[i][1] = b[top] - a[i];
top = i - 1; // t == i 表示 后面元素不能再取到超过top+1 下标Bi元素。
// 因为这会导致没有后面元素的匹配。
} else {
ans[i][0] = b[t] - a[i];
ans[i][1] = b[top] - a[i];
}
}
rep(i,1,n) cout<<ans[i][0]<<" ";puts("");
rep(i,1,n) cout<<ans[i][1]<<" "; puts("");
}
C. Fighting Tournament
题目大意: 一个是全排列的数组,每次前两个进行PK,哪个元素大哪个赢,之后将大的放前面,输的放数组后面,这样依次进行。问输入下标idx和已经比赛回合,求胜的回合是多少个。
可以知道遍历依次求每个idx的胜利回合,之后在对k进行比较判断即可。
这是因为,第一次遍历完,数组最大值在第一个,后面不管是多少都是输的,表示处最大元素外,剩下元素胜利回合是1或者0.
int a[N]; //
int wn[N]; // 每个下标胜利第一次回合
void solve() {
memset(wn,0, sizeof(wn)); int n, q; cin>>n>>q;
rep(i,1,n) cin>>a[i];
// 输入
// g 表示 g = a[i]>a[g] ? i : g;
// 表示大的元素下标
int g = 1;
rep(i,2,n) {
if(a[i] > a[g]) {
g = i;
wn[g]++;
} else {
wn[g]++;
}
}
// 0x7fffffff 是 INT_MAX
// 因为最大元素的胜利回合与k耦合的深,所以让其为max
wn[g] = 0x7fffffff;
while(q--) {
int idx, k; cin>>idx>>k;
// idx - 2 表示 减去 前面没有参加的比赛场次
k -= max(idx-2, 0); // max() 是防止 a[1] , a[2] 时是负数的情况。
cout<<max(min(k,wn[idx]),0)<<endl; // min() 是求赢得场次, 又用了max() 是剔除 {0 < k < idx - 2} 的情况;
}
}