美好高中时光

2021ccpc华为云挑战赛 B
卷业务模型分析
这道题用到了高中的知识:线性回归方程
又回想起了当时算这种题的恐惧,数据又多,有时候还贼不好算。
这里又遇到了。
在这里插入图片描述
(熟悉的公式QAQ)
所以知道了用这个这个公式,应该思路就很好想了,但依旧很恶心,写了2个小时。
先根据线性回归方程求出 大致的 k,b。然后在误差范围内枚举,符合条件输出。(这里我把b的误差设为10的时候不行,得大一点,设成20才能过)

#include <iostream>
using namespace std;
#define fi first
#define se second
typedef long long ll;
typedef pair<ll,ll>PII;
const int eps= 1e-8;
const int maxn = 1e5+10;
ll a[3][maxn],b[maxn];
int n;
PII cal(int id){

    ll sum1=0,sum2=0,X=0,Y=0;
    for(int i = 1;i <= n ;i++){
        sum1+=a[id][i]*b[i];
        sum2+=a[id][i]*a[id][i];
        X+=a[id][i];
        Y+=b[i];
    }
    double p1=1.0*X/n,p2=1.0*Y/n;
    double k=(1.0*sum1-n*p1*p2)/(1.0*sum2-n*p1*p1);
    double b=p2-k*p1;
    return make_pair((ll)k,(ll)b);
}
bool solve(){

    scanf("%d",&n);
    for(int i = 1; i <= 2 ; i++){
        for(int j = 1; j <= n ; j++){
            scanf("%lld",&a[i][j]);
        }
    }
    for(int i = 1; i <= n ; i++)scanf("%lld",&b[i]);
    PII t=cal(1);
    for(ll k = -10 ; k <= 10 ; k++){//k的误差
        ll K=t.fi+k;
        for(ll j = -20; j <= 20; j++){//b的误差
            ll B=t.se+j;int i;
            for(i = 1; i <= n ; i++){
                if(b[i]-B-K*a[1][i]>10) break;
                if(b[i]-B-K*a[1][i]<-10)break;
            }
            if(i==n+1) {
                /*cout<<t.fi << " " <<K <<" "<< t.se << " " << B<<endl;*/
                return true;
            }
        }
    }
    return false;
}
int main()
{
    int t;scanf("%d",&t);
    while(t--){
        bool f=solve();
        if(f) printf("1\n");
        else  printf("2\n");
    }
    return 0;
}


或者也可以根据i也就是误差范围找出当前的一个b然后去判断

#include <iostream>
using namespace std;
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int>PII;
const int eps= 1e-8;
const int maxn = 1e5+10;
ll a[3][maxn],b[maxn];
int n;
ll cal(int id){

    ll sum1=0,sum2=0,X=0,Y=0;
    for(int i = 1;i <= n ;i++){
        sum1+=a[id][i]*b[i];
        sum2+=a[id][i]*a[id][i];
        X+=a[id][i];
        Y+=b[i];
    }
    double p1=1.0*X/n,p2=1.0*Y/n;
    ll k=(ll)(1.0*sum1-n*p1*p2)/(1.0*sum2-n*p1*p1);
    return k;
}
bool solve(){

    scanf("%d",&n);
    for(int i = 1; i <= 2 ; i++){
        for(int j = 1; j <= n ; j++){
            scanf("%lld",&a[i][j]);
        }
    }
    for(int i = 1; i <= n ; i++)scanf("%lld",&b[i]);
    ll t=cal(1);
    for(ll k = -5 ; k <= 5 ; k++){
        for(ll j = -10; j <= 10 ; j++){
            ll B=b[1]-j-(t+k)*a[1][1];int i;//找出当前合适的b
            for(i = 2; i <= n ; i++){
                if(b[i]-B-(t+k)*a[1][i]>10) break;
                if(b[i]-B-(t+k)*a[1][i]<-10)break;
            }
            if(i==n+1) return true;
        }
    }
    return false;
}
int main()
{
    int t;scanf("%d",&t);
    while(t--){
        bool f=solve();
        if(f) printf("1\n");
        else  printf("2\n");
    }
    return 0;
}

或者不管误差直接算两种的结果,然后取误差小的

#include <iostream>
using namespace std;
#define fi first
#define se second
typedef long long ll;
typedef pair<double,double >PII;
const int eps= 1e-8;
const int maxn = 1e5+10;
ll a[3][maxn],b[maxn];
int n;
PII cal(int id){

    ll sum1=0,sum2=0,X=0,Y=0;
    for(int i = 1;i <= n ;i++){
        sum1+=a[id][i]*b[i];
        sum2+=a[id][i]*a[id][i];
        X+=a[id][i];
        Y+=b[i];
    }
    double p1=1.0*X/n,p2=1.0*Y/n;
    double k=(1.0*sum1-n*p1*p2)/(1.0*sum2-n*p1*p1);
    double b=p2-k*p1;
    return make_pair(k,b);

}
void solve(){

    scanf("%d",&n);
    for(int i = 1; i <= 2 ; i++){
        for(int j = 1; j <= n ; j++){
            scanf("%lld",&a[i][j]);
        }
    }
    for(int i = 1; i <= n ; i++)scanf("%lld",&b[i]);
    PII t1=cal(1),t2=cal(2);
    double s1=0,s2=0;
    for(int i = 1; i <= n ; i++){
        s1+=(b[i]-t1.se-t1.fi*a[1][i])*(b[i]-t1.se-t1.fi*a[1][i]);
        s2+=(b[i]-t2.se-t2.fi*a[2][i])*(b[i]-t2.se-t2.fi*a[2][i]);
    }
    if(s1-s2>eps) printf("2\n");
    else          printf("1\n");
}
int main()
{
    int t;scanf("%d",&t);
    while(t--){
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值