2019西北工业大学程序设计创新实践基地春季选拔赛(重现赛) 部分题解

A Chino with Geometry

 

思路:数学题,就是求出D,E点的坐标,然后求向量的乘积就好了,用y=k*x+b方程写出直线方程,

因为不用考虑k不存在的情况(Σ(⊙▽⊙",竟然没有其他坑)。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int main(void)
{
	double x0,y0,r,x1,y1,y2;
	scanf("%lf%lf%lf%lf%lf%lf",&x0,&y0,&r,&x1,&y1,&y2);
	double a = pow((y1-y2)/x1,2)+1;
	double b = (2*(y1-y2)*(y2-y0))/x1-2*x0;
	double c = x0*x0-r*r+(y2-y0)*(y2-y0);
	double tp = sqrt(b*b-4*a*c);
	double px1 = (-1.0*b+tp)/(2*a);
	double py1 = (y1-y2)/x1*px1+y2;
	double px2 = (-1.0*b-tp)/(2*a);
	double py2 = (y1-y2)/x1*px2+y2;
	double l1 = fabs(sqrt((x1-px1)*(x1-px1)+(y1-py1)*(y1-py1)));
	double l2 = fabs(sqrt((x1-px2)*(x1-px2)+(y1-py2)*(y1-py2)));
	printf("%.0lf\n",l1*l2);
	
	return 0;
}


B- Chino with Repeater

思路:签到题,每次最大是上一次的2倍,然后不断增加就好了。

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
int main(void)
{
	LL n,cnt=0,res=1;
	scanf("%lld",&n);
	while(res<n){
		res*=2;cnt++;
	}
	printf("%lld\n",cnt);
	return 0;
}

 

D-Chino with Equation

 

思路:这题真的困扰了我好久,最后在大佬的指导下我才做出来,思路比较简单,

(1)考虑全部正数的情况下,将n视为n个1,然后在n-1个空位中插入m-1隔板,将它们分为m个部分,

考虑这种情况总共有C(n-1,m-1)种可能。

(2)考虑非负数的情况,视为n个1和m-1个挡板排列,然后将其分为m个部分,如果挡板的某一边没有数字就说明这个挡板的一边是0,考虑了非负数的情况。

然后就是求解C(n,m)的问题了用卢卡斯算法就好了

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL MOD = 1e9+7;
LL POW(LL a,LL b){
	LL ret = 1;
	while(b){
		if(b&1) ret = ret*a%MOD;
		a = a*a%MOD;
		b>>=1;
	}
	return ret;
}
LL C(LL n,LL m){
	if(m>n) return 0;
	LL i,j,a = 1,b = 1;
	for(i = n-m+1;i<=n;i++) a = a*i%MOD;
	for(i = 2;i<=m;i++) b = b*i%MOD;
	return a*POW(b,MOD-2)%MOD;
}
LL Lucas(LL n,LL m){
	int i,j;
	if(!m) return 1;
	else return (C(n%MOD,m%MOD)*Lucas(n/MOD,m/MOD))%MOD;
}
int main(void)
{
	LL n,m;
	scanf("%lld%lld",&m,&n);
	printf("%lld %lld\n",Lucas(n-1,m-1),Lucas(n+m-1,m-1));
	return 0;
}

 

F-Chino with Expectation

 

思路:

“数学期望就是所有可能的结果乘以概率”,

“数学期望就是所有可能的结果乘以概率”,

“数学期望就是所有可能的结果乘以概率”,

重要的事情说三遍,每次考虑xi可能加在1~n中不同的数的可能性是相同的,

所以对于输入数据的第一次查询的[l,r]区间的期望有n种可能。

(1)x加在a1上 EX = 2*1/5 + 3*1/5 = 2.5;

(2)x加在a2上 EX = 3*1/5 + 3*1/5 = 3;

 

依次类推,求出每种EX的结果与概率,

X2.53.03.02.52.5
P0.20.20.20.20.2

 

 

 

所以总期望是SUM = (2.5+3.0+3.0+2.5+2.5)*0.2 = 2.7。

由于数据较大,用前缀和优化一下就好了。

 

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 100100;
int a[maxn],pre[maxn];
int main(void)
{
	int n,i,j,x,l,r,q,sum=0,tp;
	pre[0]=0;
	scanf("%d%d",&n,&q);
	for(i=1;i<=n;i++){
		scanf("%d",&a[i]);
		pre[i]=a[i]+pre[i-1];
		sum+=a[i];
	}
	double t1,t2,ans;
	while(q--){
		scanf("%d%d%d",&x,&l,&r);
		t1 = pre[r]-pre[l-1];
		t2 = t1+x;
		ans = (t1*(n-(r-l+1))+t2*(r-l+1))/(1.0*n*(r-l+1));
		printf("%.6lf\n",ans);
	}
	return 0;
}

 

G-Chino with Train to the Rabbit Town

 

思路:

参考了jerryandtom的代码,感觉他的想法很棒。

利用异或的性质a^a = 0,所以,用数组sumi记录前i项的异或和,然后每次标记sumi,

判断sumi^m是否为出现过,如果出现过,(ax^……ai = m),因为相当于将(ax^……^ai再次^m = 0),就回到了

第x-1项,然后更新标记的结束节点为i。

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 500100;
int pos[maxn],sum[maxn]={0},a[maxn];
int main(void)
{
	int n,m,i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]^a[i];
	fill(pos,pos+maxn,-1);
	int bj = -1,ans = 0,tp;
	pos[0] = 0;
	for(i=1;i<=n;i++){
		tp = sum[i]^m;
		if(pos[tp]>=bj&&pos[tp]!=-1){
			ans++;
			bj = i;
		}
		pos[sum[i]] = i;
	}
	printf("%d\n",ans);
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值