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;
}