CF 2*1400 做题反馈

博主分享了自己在算法竞赛中的经验教训,强调了避免惯性思维和过度修补代码的重要性。第一题涉及数组的最小最大元素计算,通过从后往前遍历寻找匹配元素。第二题是关于全排列数组的PK问题,通过遍历计算每个元素的胜利回合。解决方案分别给出了详细的代码实现。
摘要由CSDN通过智能技术生成

  今晚做了两道题。
  第一道第一部分思路是对的,但是第二部分出了岔子。两部分问题相似,我以为是跟第一部分的处理方式相似,就一直在凑,导致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} 的情况;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

golemon.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值