NOIP2019模拟赛(二)03.10

2022-09-19 12:39:12 浏览数 (2)

NOIP2019模拟赛(二)03.10

T1

题意

题面

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

数据范围

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

思路

对于20%的数据

你开longquad 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 '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 '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("%.5lfn",(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 '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 '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;
}

0 人点赞