Rating 上了一点,考试时本来可以多得五十分的。。
P1 A^B Problem
题面
给出 $A$ 和 $B$,求 $A^B$ ,其中 $A$ 为浮点数,输出也为浮点数。
思路
高精水题,先去掉小数点求幂,再加上即可。
有 Python 打什么高精
from decimal import *
getcontext().prec=50000
s=input().split()
a=Decimal(s[0])
b=Decimal(s[1])
if a!=0:
ans=format(pow(a,b))
if ans[0]=='0' and len(ans)>1:
ans=ans[1:]
while ans[-1]=='0' or ans[-1]=='.':
ans=ans[:-1]
print(ans)
else:
if b==0:
print("1")
else:
print("0")
P2 猜数游戏
题面
有一个 $n$ 个数的可重集合,小 A 会选择一个数,但不会告诉你这个数,让 B 猜它的最小质因数。B 每次可以选出一些数,问 A 他选择的数属不属于这个集合,A 只回答 “是” 或 “否”。
B 想知道最优方案中,最坏情况下要询问几次,和最小的期望询问次数。
思路
题目问的是最小质因数,所以和集合内的数没关系,直接处理出每个数的最小质因数。
对于最坏情况下的询问次数,即是二分的次数。设最小质因数有 $k$ 种,答案为 $\left \lceil log_2(k) \right \rceil$。
最优情况下,使用贪心策略,在每种质因数个数的集合中每次取两个最大值,累计期望,然后再插入这两个值的和,直到集合还剩下一个元素为止。(类似于合并果子)
代码
#include<bits/stdc++.h>
using namespace std;
long long n,s[1000000];
long long zs(long long x){
if (x%2==0){
return 2;
}
int p=sqrt(x);
for (long long i=3;i<=p+1;i+=2){
if (x%i==0){
return i;
}
}
return x;
}
long long top=0,t[1000000];
map<int,int> m;
int main(){
cin>>n;
long long x;
for (long long i=1;i<=n;i++){
scanf("%d",&x);
if (!m[x]){
t[++top]=x;
}
m[x]++;
}
cout<<ceil(log(top)/log(2))<<endl;
priority_queue<int,vector<int>,greater<int> > q;
for (long long i=1;i<=top;i++){
q.push(m[t[i]]);
}
top--;
long long ans=0;
while (q.size()>1){
long long tmp=0;
tmp+=q.top();
q.pop();
tmp+=q.top();
q.pop();
ans+=tmp;
q.push(tmp);
}
printf("%.6lf",ans*1.00/n);
}
P3 洪水 (富金森林公园)
题面
思路
因为高度 $h_i <= 10^9$ 所以先离散化一遍。
然后用线段树维护每个高度贡献。(差分思想)
几乎是照着题解打的,有空要再打一遍。
代码
#include<bits/stdc++.h>
#define MAXN 500005
using namespace std;
inline int read(){
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
long long sum[MAXN*4],min[MAXN*4],max[MAXN*4],tag[MAXN*4];
void pushup(int rt){
sum[rt]=sum[rt*2]+sum[rt*2+1];
}
void build(int l,int r,int rt){
if(l==r){
sum[rt]=0;
return;
}
int m=(l+r)/2;
build(l,m,rt*2);
build(m+1,r,rt*2+1);
pushup(rt);
}
void pushdown(int rt,int ln,int rn){
if(tag[rt]){
sum[rt*2]+=ln*tag[rt];
sum[rt*2+1]+=rn*tag[rt];
tag[rt*2]+=tag[rt];
tag[rt*2+1]+=tag[rt];
tag[rt]=0;
}
}
void update(int L,int R,long long C,int l,int r,int rt){
if(L<=l&&r<=R){
sum[rt]+=C*(r-l+1);
tag[rt]+=C;
return ;
}
int m=(l+r)/2;
pushdown(rt,m-l+1,r-m);
if(L<=m){
update(L,R,C,l,m,rt*2);
}
if(R>m){
update(L,R,C,m+1,r,rt*2+1);
}
pushup(rt);
}
long long query(int L,int R,int l,int r,int rt){
long long ans=0;
int m=(l+r)/2;
if(L<=l&&R>=r){
return sum[rt];
}
pushdown(rt,m-l+1,r-m);
if(L<=m){
ans+=query(L,R,l,m,rt*2);
}
if(R>m){
ans+=query(L,R,m+1,r,rt*2+1);
}
return ans;
}
struct node{
int x,y,id,p;//要修改的编号(如果当前要修改),高度,读入顺序,离散化后编号
int t,a,b;
};
node s[MAXN];
int n,q;
bool cmp(node a,node b){
return a.y<b.y;
}
bool cmp2(node a,node b){
return a.id<b.id;
}
int main(){
cin>>n>>q;
for (int i=1;i<=n;i++){
s[i].y=read();
s[i].id=i;
}
for (int i=n+1;i<=n+q;i++){
s[i].t=read();
if (s[i].t==2){
s[i].x=read();
}
s[i].y=read();
s[i].id=i;
}
sort(s+1,s+1+n+q,cmp);
s[1].p=1;
for (int i=2;i<=n+q;i++){
if (s[i].y!=s[i-1].y){
s[i].p=s[i-1].p+1;
}else{
s[i].p=s[i-1].p;
}
}
int tot=s[n+q].p;//离散后最大高度
build(1,tot,1);
sort(s+1,s+1+n+q,cmp2);//重新按照id排序
s[0].p=0;//修改边界外点的高度便于计算
for (int i=1;i<=n;i++){
if (s[i-1].p<s[i].p){
update(s[i-1].p+1,s[i].p,1,1,tot,1);
}
}
for (int i=n+1;i<=n+q;i++){
if (s[i].t==1){
printf("%d\n",query(s[i].p,s[i].p,1,tot,1));
}else{
int tar=s[i].x;
if (s[tar-1].p<s[tar].p){
update(s[tar-1].p+1,s[tar].p,-1,1,tot,1);
}
if (tar!=n&&s[tar].p<s[tar+1].p){
update(s[tar].p+1,s[tar+1].p,-1,1,tot,1);
}
s[tar].p=s[i].p;
if (s[tar-1].p<s[tar].p){
update(s[tar-1].p+1,s[tar].p,1,1,tot,1);
}
if (tar!=n&&s[tar].p<s[tar+1].p){
update(s[tar].p+1,s[tar+1].p,1,1,tot,1);
}
}
}
}
