思路:数学题,就是求出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;
}
思路:签到题,每次最大是上一次的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;
}
思路:这题真的困扰了我好久,最后在大佬的指导下我才做出来,思路比较简单,
(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;
}
思路:
“数学期望就是所有可能的结果乘以概率”,
“数学期望就是所有可能的结果乘以概率”,
“数学期望就是所有可能的结果乘以概率”,
重要的事情说三遍,每次考虑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的结果与概率,
X | 2.5 | 3.0 | 3.0 | 2.5 | 2.5 |
P | 0.2 | 0.2 | 0.2 | 0.2 | 0.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;
}