前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NOIP2019模拟赛(二)03.10

NOIP2019模拟赛(二)03.10

作者头像
yzxoi
发布2022-09-19 12:39:12
3560
发布2022-09-19 12:39:12
举报
文章被收录于专栏:OI

NOIP2019模拟赛(二)03.10

T1

题意

题面

给定两个数a,b求出ba相乘的结果。

数据范围

保证a \leq 99.9999 ,b \leq 25a的有效数字不超过6位。

思路

对于20%的数据

你开long\quad double就好了呀。

对于100%的数据

你写高精度就好了呀。 说得很轻巧,但是打比赛的时候花了30分钟。。。 差不多分两个步骤: 1. 把a的小数转化为整数,并且求出a^b 2. 然后再点一个小数点就好了 坑:0.52要输出成.52。 其他没啥了。

代码语言:javascript
复制
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
using namespace std;
inline int read(){
    int res=0,f=1;char ch=getchar();
    while(ch<'0'ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else{
        write(x/10);
        putchar(x%10+'0');
    }
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
char A[50010];int b,len,Dot=-1;
int a[5000010];
int t[5000010];
int c[5000010],Len;
int top=0;
void Mul(){//高精度乘法
    int lena=top,lent=Len;
    for(int i=0;i<lent/2;i++) swap(t[i],t[lent-i-1]);
    int u=0;memset(c,0,sizeof(c));
    for(int i=0;i<lena;i++){
        for(int j=0;j<lent;j++){
            c[i+j]+=a[i]*t[j]+u;
            u=c[i+j]/10;
            c[i+j]%=10;
        }
        c[i+lent]=u;u=0;
    }
    Len=lena+lent;
    while(c[Len]==0) Len--;++Len;
    memset(t,0,sizeof(t));
    for(int i=0;i<Len;i++) t[i]=c[i];
    for(int i=0;i<Len/2;i++) swap(t[i],t[Len-i-1]);
}
int main(){
    cin>>A;b=read();len=strlen(A);
    for(int i=0;i<len;i++){
        if(A[i]=='.'){
            Dot=i;//寻找小数点
            continue ;
        }
        t[top]=a[top]=A[i]-'0';
        ++top;
    }
    if(Dot!=-1)
    Dot=len-Dot-1;else Dot=0;//计算出小数点离个位多少位
    for(int i=0;i<top/2;i++) swap(a[i],a[top-i-1]);
    Len=top;
    for(int i=1;i<b;i++){
        Mul();
    }
    Dot=Dot*b;//计算出小数点应该点在哪里
    if(Dot>=Len){//需要输出成.000xxx的形式
        cout<<".";
        for(int i=Len;i<Dot;i++) cout<<'0';
        for(int i=0;i<Len;i++) cout<<t[i];cout<<endl;
    }else{
        for(int i=0;i<Len;i++){
            if(i==Len-Dot){
                cout<<".";//小数点
            }
            cout<<t[i];
        }
        cout<<endl;
    }
    return 0;
}

T2

题意

有两个人很无聊地在玩猜数游戏。某个人想出来一个n个正整数的集合,然后选择一个数,让另外一个人猜他选的数的最小质因子。 问:在最优的方案中,最坏情况下需要询问几次,以及最小的询问期望次数? 注:询问期望次数是所有数需要的询问次数的平均值,最坏情况的询问次数为所有数的询问次数的最大值。

思路

很显然这道题和小学奥数题很像。就比如说问有1~n的数,怎样询问能最少? 显然是log2次。 就像这样:↓↓↓

那么对于第二个询问呢?和Luogu的合并果子很像。 Luogu 合并果子 其实就是利用哈夫曼树的原理,每次寻找最小的两个像上面一样log2地合并起来就好了。 可以使用priority_queue的小根堆。 注意:这道题会卡时,所以需要预处理出素数。

代码语言:javascript
复制
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
using namespace std;
inline int read(){
    int res=0,f=1;char ch=getchar();
    while(ch<'0'ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else{
        write(x/10);
        putchar(x%10+'0');
    }
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
int n,a[100010],m=0,t[100010],p[100010];
int vis[100010],tot;
priority_queue<int ,vector<int>, greater<int> > Hf;
int GetLog(int x){
    int pp=1;
    while(x!=1){
        pp++;x/=2;
    }
    return pp;
}
void GetPrime(){//预处理素数
    for(int i=2;i<=100000;i++){
        if(vis[i]==0){
            p[++tot]=i;
            for(int j=i;j<=100000;j+=i) vis[j]=1;
        }
    }
}
int main(){
    GetPrime();
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++){
        int fst=sqrt(a[i])+1;
        for(int j=1;j<=tot&&p[j]<=fst;j++){
            if(a[i]%p[j]==0){
                a[i]=p[j];//找到该数的最小质因子
                break;
            }
        }
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++){
        if(a[i]!=a[i-1]) m++;//去重
        t[m]++;
    }
    int ans;
    if(m<=2) puts("0");
    else {
        ans=log2((m-1)<<1);
        write(ans),putchar('\n');
    }
    for(int i=1;i<=m;i++) Hf.push(t[i]);
    ans=0;
    for(int i=1;i<m;i++){
        int x=Hf.top();Hf.pop();
        int y=Hf.top();Hf.pop();
        ans+=x+y;//哈夫曼树思想
        Hf.push(x+y);
    }
    printf("%.5lf\n",(double)ans/(double)n);
    return 0;
}

T3

题意

这和Luogu某题很像

题面

n块石头,有m个询问。首先给出这n块石头的高度。然后对于每一次的询问有两种: 1. 读入一个整数x,询问大于或等于的连续的石头的部分的个数。 2. 读入两个整数x,y,表示将第x块石头的高度修改为y

样例输入

5 4 8 6 3 5 4 1 5 2 4 1 1 5 1 3

样例输出

2 1 2

样例解释

第一次询问时,洪水高度为5 ,露出水面的岩石的编号为{1,2,4}连续的部分为{1,2}{4},答案是2 第二次询问时,洪水高度为5,露出水面的岩石的编号为{1,2}连续的部分为{1,2},答案是1 第三次询问时,洪水高度为3,露出水面的岩石的编号为{1,2,3,5}连续的部分为{1,2,3}{5},答案是2

思路

对于50%的数据

我们可以采用暴力(废话) 所以我们就对于每个查询询问暴力。 结果真的只有50分。。。(出题人也太狠了吧)

代码语言:javascript
复制
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define int long long
#define MAXN 100010*4
using namespace std;
inline int read(){
    int res=0,f=1;char ch=getchar();
    while(ch<'0'ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else{
        write(x/10);
        putchar(x%10+'0');
    }
}
int n,m,a[200010],c[200010];
signed main(){
    n=read();m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int op,x,y,i=1;i<=m;i++){
        op=read();
        if(op==1){
            x=read();int ans=0;
            for(int j=1;j<=n;j++){
                if(a[j]>=x) ans++;
            }
            for(int j=1;j<=n;j++){
                if(a[j]>=x&&a[j-1]>=x) ans--;
            }
            write(ans);putchar('\n');
        }else{
            x=read();y=read();
            a[x]=y;
        }
    }
    return 0;
}

对于100%的数据

通过观察,我们可以发现,对于每一个询问Q,其实就是寻找满足:h[i-1]<Q \leq h[i]h[i-1]<h[i](h[i-1]+1,h[i])这个答案区间就可加1。而对于每一个询问,只需要输出答案区间内的Ans[Q]即可。对于每一个修改,影响到的只有h[i-1]h[i+1]所以,再重新分别判断一次即可。 注意:每一次的修改需要先清空上一次对于该点的修改。

代码语言:javascript
复制
#include<bits/stdc++.h>
#define MAXN 2000010
using namespace std;
#define int long long
inline int read(){
    char ch=getchar();int res=0,f=1;
    while(ch<'0'ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else{
        write(x/10);
        putchar(x%10+'0');
    }
}
int c[MAXN],h[MAXN];
int n,m,N;
int tree[4*MAXN],add[4*MAXN],num[MAXN],Max;
inline void build(int l,int r,int root){//线段树模板走起
    if (l==r){tree[root]=num[l];return;}
    int mid=(l+r)/2;
    build(l,mid,root*2);
    build(mid+1,r,root*2+1);
    tree[root]=tree[root*2]+tree[root*2+1];
}
inline void updata(int l,int r,int root,int x,int ans){
    if(r<xl>x) return;
    if(l==r&&l==x){tree[root]+=ans;return;}
    int mid=(l+r)/2;
    updata(l,mid,root*2,x,ans);
    updata(mid+1,r,root*2+1,x,ans);
    tree[root]=tree[root*2]+tree[root*2+1];
}
inline void modify(int root,int maxl,int maxr,int l,int r,int v){
    if (maxl>=l&&maxr<=r){add[root]+=v;return;}
    tree[root]+=(min(maxr,r)-max(maxl,l)+1)*v;
    int mid=(maxl+maxr)/2;
    if (l<=mid) modify(root*2,maxl,mid,l,r,v);
    if (mid<r) modify(root*2+1,mid+1,maxr,l,r,v);
}
inline int Search(int maxl,int maxr,int root,int l,int r){
    if (maxl>rmaxr<l) return 0;
    if (l<=maxl&&maxr<=r) return tree[root]+(maxr-maxl+1)*add[root];
    int mid=(maxl+maxr)/2;
    int res=(min(maxr,r)-max(maxl,l)+1)*add[root];
    if (l<=mid) res+=Search(maxl,mid,root*2,l,r);
    if (mid<r) res+=Search(mid+1,maxr,root*2+1,l,r);
    return res;
}//线段树模板结束
int X,top,x[MAXN],k[MAXN],J[MAXN],Las[MAXN];
struct node{
    int x,xx,id,h;
}a[MAXN];
int f[MAXN],g[MAXN],tot,tot2,mx;
bool cmp(node qx,node qy){
    return qx.x<qy.x;
}
signed main(){
    n=read();m=read();
    for(int i=1;i<=n;i++){
        a[i].x=read();
        a[i].id=i;
    }
    for(int i=n+1;i<=m+n;i++){
        J[i]=read();
        if(J[i]==2) Las[i]=read();
        a[i].x=read();
        a[i].id=i;
    }
    sort(a+1,a+n+m+1,cmp);
    f[a[1].id]=1;
    for(int i=2;i<=n+m;i++){
        if(a[i].x>a[i-1].x) f[a[i].id]=f[a[i-1].id]+1;
        else f[a[i].id]=f[a[i-1].id];
    }
    Max=f[a[n+m].id];
    build(1,Max,1);
    for(int i=1;i<=n;i++)
        if(f[i-1]<f[i]) modify(1,1,Max,f[i-1]+1,f[i],1);//预处理
    for(int i=n+1;i<=n+m;++i){
        if(J[i]==2){
            int j=Las[i];
            if(f[j-1]<f[j]) modify(1,1,Max,f[j-1]+1,f[j],-1);
            if(j!=n&&f[j]<f[j+1]) modify(1,1,Max,f[j]+1,f[j+1],-1);//清空上一次的修改操作
            f[j]=f[i];//进行新的一次操作
            if(f[j-1]<f[j]) modify(1,1,Max,f[j-1]+1,f[j],1);
            if(j!=n&&f[j]<f[j+1]) modify(1,1,Max,f[j]+1,f[j+1],1);
        }else write(Search(1,Max,1,f[i],f[i])),putchar('\n');//输出该点的值(单点查询)
    }
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-03-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NOIP2019模拟赛(二)03.10
  • T1
    • 题意
      • 题面
      • 数据范围
    • 思路
      • 对于20%的数据
      • 对于100%的数据
  • T2
    • 题意
      • 思路
      • T3
        • 题意
          • 题面
          • 样例输入
          • 样例输出
          • 样例解释
        • 思路
          • 对于50%的数据
          • 对于100%的数据
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档