csp_202012-2期末预测之最佳阈值(一维前缀和)

题目链接
csp_202012-2期末预测之最佳阈值(一维前缀和)
csp_202012-2期末预测之最佳阈值(一维前缀和)
csp_202012-2期末预测之最佳阈值(一维前缀和)
csp_202012-2期末预测之最佳阈值(一维前缀和)
暴力的写法很简单,就是依次拿每一个同学的y值作为阈值theta,然后统计预测正确的数目,如果遇到能让预测数目更大的theta,就更新theta*和相应的预测正确的数目,双重for循环即可。

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int y[100005],result[100005];
int main() {
    int m;
    cin >> m;
    for(int i=0;i<m;i++){
        cin >> y[i] >> result[i];
    }
    int ans=0,maxp=0;
    for(int i=0;i<m;i++){
        int temp=0;//记录预测正确的数目
        int theta=y[i];
        for(int j=0;j<m;j++){
            if((y[j]>=theta && result[j]==1) || (y[j]<theta && result[j]==0))
                temp++;
        }
        if(temp>=maxp){
            maxp=temp;
            ans=theta;
        }
    }
    cout << ans;
    return 0;
}

但是这样暴力只能拿50分,所以还要想新的路子。
csp_202012-2期末预测之最佳阈值(一维前缀和)
观察第一个样例,这个样例已经按照yi的值升序排列了,当i=4,我们取阈值theta=3, 那么当i≥4时,yi≥y4,所以预测正确的数目就是i≥4时1的数目,i≤3时yi<y4,所以预测正确的数目就是i≤3时0的数目,总的预测正确的数目就是两者之和。为了O(1)的得到1的数目,就可以采用一维前缀和,sum[i]表示前i个数字的result之和(包括第i个),这其实就是1的数目了,因此预测正确的数目表达式:

(i-1-sum[i-1])+(sum[m]-sum[i-1])

当yi相同的时候(如下例中y2=y3=y4=y5),我们只需要对第一个yi进行计算(也就是y2),后面相同的可以直接跳过(即不用计算y3 y4 y5),以theta=y2=1为例,当yi≥1时,result=1就是预测正确,因为当i≥2时,都有yi≥y2,因此我们只需要关注有多少个result=1,对于值相同的yi(这里的y2 y3 y4 y5),他们对应的result的0和1的顺序是无所谓的;但是yi相同时一定要只计算下标i最小的情形,如按照上式计算i=4,那么公式是错误的,因为i=2和3时预测也是正确的,但是公式在i≤3时只计算了0的数目。体现在最终的代码中就是continue语句的作用。
csp_202012-2期末预测之最佳阈值(一维前缀和)编写代码时还要注意的问题是:
1.debug的时候把数组大小从100005改到8,提交之前要记得改回去
2.sort函数的用法
使用sort函数对结构体进行排序,要注意函数参数,数组长度是len,从temp到temp+len进行排序,因为是前闭后开的

bool cmp(example x, example y)
{
    return x.a<y.a;
    //<升序,>降序,x.a以a排序,x.b以b排序
}

struct example
{
    int a,b;
}temp[len];

int main(void)
{
//...
    sort(temp, temp+len, cmp);
//...
}

完整代码如下:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
struct Stu{
    int y,result;
}stu[100005];
int sump[100005]={0};//前缀和,用来累加多少个1
bool cmp(struct Stu a,struct Stu b){//按照y进行升序排序,不用根据0 1进行二次排序,(结合后面continue语句)
    return a.y < b.y;//升序
}
int main(){

    int m;
    cin >> m;
    for(int i=1;i<=m;i++){
        cin >> stu[i].y >> stu[i].result;
    }
    sort(stu+1,stu+m+1,cmp);//注意排序范围

    for(int i=1;i<=m;i++){
        if(stu[i].result==1){
            sump[i]=sump[i-1]+1;
        }else sump[i]=sump[i-1];
    }
    int ans=0,maxp=0;
    ans=stu[1].y;//先拿第一个y作为预测值
    maxp=sump[m]-sump[0];//对应的预测正确的数目
    for(int i=2;i<=m;i++){
        //以当前的stu[i].y作为theta,前面有sump[i-1]个1,即预测错这么多,预测对的有i-1-sum[i-1]个,后面的1的数目是预测正确的
        if(stu[i].y==stu[i-1].y) continue;//遇到y相同的只需要对第一次遇到的进行计算更新,0 1的顺序不重要,因为只需要知道1的数目
        int temp=(i-1-sump[i-1]) + (sump[m]- sump[i-1]);
        if(temp>=maxp){
            maxp=temp;
            ans=stu[i].y;
        }
    }
    cout << ans;
    return 0;
}
上一篇:Udesk全场景客服系统FAQ分享(202012期)


下一篇:CCF 202012-1-期末预测之最佳阈值