2020牛客寒假算法基础集训营4【A - I】

题目来源:https://ac.nowcoder.com/acm/contest/3005#question
这场居然没人AK,难度真的不小啊(后两题都没看)


A - 欧几里得

在这里插入图片描述
第一题跟着递归式子反递推就好了,假如我们现在某一步是 x y 那下一步递归是 a b
那么a=y , b=x%y 即可得 上一步是 ak+b , b 取k=1时最小

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    int t;
    r(t);
    while(t--){
        r(n);
        LL a=1,b=0;
        if(n>=1){
            a=2; b=1;
            n--;
        }
        FOR(i,1,n){
            LL tmp=a;
            a=a+b;
            b=tmp;
        }
        cout<<a+b<<endl;
    }
    return 0;
}


B - 括号序列

类似括号匹配,丢到栈里面 有一对就出栈,最后看栈是否为空

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
char s[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    scanf("%s",s+1);
    int len=strlen(s+1);
    stack<char> ss;
    FOR(i,1,len){
        if(ss.size()){
            char c=ss.top();
            if(c=='('&&s[i]==')') ss.pop();
            else if(c=='{'&&s[i]=='}') ss.pop();
            else if(c=='['&&s[i]==']') ss.pop();
            else ss.push(s[i]);
        }
        else ss.push(s[i]);
    }
    if(ss.size()) cout<<"No\n";
    else cout<<"Yes\n";
    return 0;
}


C - 子段乘积

我又是线段树,其实可以不用,做个标记哪些值为0,哪些不会0就好了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
LL f[N];
LL sum[N<<2];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
LL qpow(LL a,LL p)
{
    LL res=1;
    while(p){
        if(p&1) res=res*a%mod;
        a=a*a%mod;
        p>>=1;
    }
    return res;
}
LL inv(LL x)
{
    return qpow(x,mod-2);
}
void build(int k,int l,int r)
{
    if(l==r){
        sum[k]=f[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(ls); build(rs);
    sum[k]=sum[k<<1]*sum[k<<1|1]%mod;
}
LL query(int k,int l,int r,int x,int y)
{
    if(x<=l&&r<=y){
        return sum[k];
    }
    int mid=(l+r)>>1;
    LL res=1;
    if(mid>=x) res=res*query(ls,x,y)%mod;
    if(mid<y) res=res*query(rs,x,y)%mod;
    return res;
}
int main()
{
    r(n); r(m);
    LL now=1;
    FOR(i,1,n){
        r(f[i]);
    }
    build(1,1,n);
    LL ans=0;
    FOR(i,m,n){
        ans=max(ans,query(1,1,n,i-m+1,i));
    }
    cout<<ans<<endl;
    return 0;
}


D - 子段异或

假如第i为开头到第j为的连续子串异或为0,那么此时1到j的前缀异或就等于1到i-1的前缀异或,我们用map记录前缀异或即可

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
LL f[N];
LL sum[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    r(n);
    map<LL,LL> mm;
    FOR(i,1,n){
        r(f[i]);
        sum[i]=sum[i-1]^f[i];
        mm[sum[i]]++;
    }
    LL now=0;
    LL ans=0;
    FOR(i,1,n){
        //cout<<sum[i-1]<<'x'<<endl;
        if(i>1) mm[sum[i-1]]--;
        if(mm.count(sum[i-1])) ans+=mm[sum[i-1]];

        //cout<<ans<<endl;
    }
    cout<<ans<<endl;
    return 0;
}


E - 最小表达式

有种高精度加法的感觉,但是我们可以优化,每次只加一个位的某个数

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
char str[N];
char num[N];
int ans[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
void add(int x,int pos)
{
//    cout<<x<<' '<<pos<<endl;
    int sum=ans[pos]+x;
//    cout<<sum<<endl;
    if(sum>=10){
        ans[pos]=sum%10;
        int i=pos+1;
//        cout<<i<<endl;
        while(ans[i]+1>=10){
            ans[i]=0;
            i++;
        }
        ans[i]++;
    }
    else ans[pos]=sum;
//    for(int i=pos+4;i>=1;i--) cout<<ans[i];
//    cout<<endl;
}
bool cmp(char a,char b)
{
    return a>b;
}
int main()
{
    scanf("%s",str+1);
    int len=strlen(str+1);
    int add_num=0;
    int cnt=0;
    FOR(i,1,len){
        if(str[i]=='+') add_num++;
        else num[++cnt]=str[i];
    }
    int sep=add_num+1;
    memset(ans,0,sizeof ans);
    sort(num+1,num+cnt+1,cmp);
    int now=0,pos=1;
    FOR(i,1,cnt){
        now++;
        add(num[i]-'0',pos);
        if(now==sep){
            now=0;
            pos++;
        }
    }
    int get=-1;
    for(int i=5e5+100;i>=1;i--)
    if(ans[i]!=0){
        get=i;
        break;
    }
    //cout<<get<<endl;
    for(int i=get;i>=1;i--) printf("%d",ans[i]);
    cout<<endl;
    return 0;
}


F - 树上博弈

不难发现,只有两人相距偶数条边时,必胜,遍历一遍图,找到所有点到根的距离 记录奇偶点个数即可

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
vector<int> v[N];
int num[N];
struct node
{
    int v,step;
};
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
void bfs(int x)
{
    node p;
    p.v=x; p.step=0;
    queue<node> q;
    q.push(p);
    while(q.size()){
        node now=q.front();
        q.pop();
        num[now.v]=now.step;
        for(int i=0;i<v[now.v].size();i++){
            node next;
            next.v=v[now.v][i];
            next.step=now.step+1;
            q.push(next);
        }
    }
}
int main()
{
    r(n);
    FOR(i,1,n-1){
        int a;r(a);
        v[a].push_back(i+1);
    }
    num[1]=0;
    bfs(1);
    int cnt1=0,cnt2=0;
    LL ans=0;
    FOR(i,1,n){
        if(num[i]&1) cnt1++;
        else cnt2++;
    }
    ans+=1ll*cnt1*(cnt1-1);
    ans+=1ll*cnt2*(cnt2-1);
    cout<<ans<<endl;
    return 0;
}


G - 音乐鉴赏

二分答案,对于每个mid,最多只有始终概率,通过n*p就可以算出期望

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int num[20];
double p[20];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    r(n);
    FOR(i,1,n){
        int a;
        r(a);
        num[a-90]++;
    }
    double l=0,r=1;
    while(r-l>=eps){
        double mid=(l+r)/2;
        double res=0;
        FOR(i,1,10){
            p[i]=(90.0-(i+90)*(1-mid))/mid;
            p[i]=1.0-p[i]/90;
            if(p[i]>1) p[i]=1;
            res+=p[i]*num[i];
        }
        //cout<<(res>=n/10)<<endl;
        if(res>=n/10) l=mid+eps;
        else r=mid-eps;
    }
    printf("%.2f%%\n",100*l);
    return 0;
}


H - 坐火车

线段树写的,我看出题人那个思维我还是不习惯,自己想了一个写法。
先用g统计1到n颜色的总数量,然后gg统计1到i-1的颜色数量,每次都只改变一个点,我们只需要更新这个点的颜色贡献,贡献值为res=1ll*(g[f[i].c]-1-gg[f[i].c])*gg[f[i].c]; 然后查询就好了。这题有点卡常,加了个ll rr就A了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=5e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
struct in
{
    int c,l,r;
}f[N];
LL g[N];
LL gg[N];
LL sum[N<<2];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
void update(int k,int l,int r,int pos,LL v)
{
    if(l==r){
        sum[k]=v;
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=pos) update(ls,pos,v);
    else update(rs,pos,v);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}
LL query(int k,int l,int r,int x,int y)
{
    if(x<=l&&r<=y){
        return sum[k];
    }
    int mid=(l+r)>>1;
    LL res=0;
    if(mid>=x) res+=query(ls,x,y);
    if(mid<y) res+=query(rs,x,y);
    return res;
}
int main()
{
    r(n);
    int ll=INF,rr=0;
    FOR(i,1,n){
        rrr(f[i].c,f[i].l,f[i].r);
        g[f[i].c]++;
        ll=min(f[i].c,ll);
        rr=max(f[i].c,rr);
    }
    LL res;
    FOR(i,1,n){
        if(f[i].l<=f[i].c&&f[i].c<=f[i].r){
            res=1ll*(g[f[i].c]-1-gg[f[i].c])*gg[f[i].c];
            update(1,ll,rr,f[i].c,res);
        }
        cout<<query(1,ll,rr,f[i].l,f[i].r)<<' ';
        gg[f[i].c]++;
        res=1ll*(g[f[i].c]-gg[f[i].c])*gg[f[i].c];
        update(1,ll,rr,f[i].c,res);
    }
    return 0;
}

I - 匹配星星

这题是个贪心。
思路先对原来的按x的大小排序,从左到右遍历,碰到z=0的就将其加入multiset,碰到z=1的就判断集合里面有没有y小于它的,找到最大的那个y从集合中删去,这就匹配了一对,具体贪心证明请看
https://ac.nowcoder.com/discuss/365889?type=101&order=0&pos=9&page=3

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
struct node
{
    int x,y,z;
}f[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
bool cmp(node a,node b)
{
    return a.x<b.x;
}
int main()
{
    r(n);
    FOR(i,1,n){
        rrr(f[i].x,f[i].y,f[i].z);
    }
    sort(f+1,f+n+1,cmp);
    multiset<int> s;
    multiset<int>::iterator it;
    int ans=0;
    FOR(i,1,n){
        if(f[i].z){
            if(s.size()){
                it=s.lower_bound(f[i].y);
                if(it!=s.begin()){
                    it--;
                    s.erase(it);
                    ans++;
                }
            }
        }
        else s.insert(f[i].y);
    }
    cout<<ans<<endl;
    return 0;
}


J - 二维跑步


发布了71 篇原创文章 · 获赞 89 · 访问量 8512

猜你喜欢

转载自blog.csdn.net/weixin_43890662/article/details/104267059