zoukankan      html  css  js  c++  java
  • 长沙学院2021校赛题解

    比赛链接

    听了偶像的话,决定也来写一写题解哈哈哈~

    可能编码风格不是很好orz

    题解写得不好!凑合着看吧~

    A水题

    将一个正实数四舍五入。

    因为输入的浮点数长度小于等于2000,已经超过了double的数据范围,所以我是用字符串做的。

    先判断是否存在小数点,不存在的话直接输出。

    存在的话判断小数点后一位的数是否大于等于5来决定是否进位。

    char s[maxn];
    void solve()
    {
        scanf("%s",s);
        int pos=-1,len=strlen(s);
        rep(i,0,len-1)if(s[i]=='.')pos=i;
        if(pos==-1)
        {
            printf("%s
    ",s);
            return;
        }
        if(s[pos+1]<'5')
        {
            rep(i,0,pos-1)printf("%c",s[i]);
            puts("");
            return;
        }
        pos--;
        rep(i,0,pos)s[i]-='0';
        bool ju=0;
        s[pos]++;
        int pp=pos;
        while(1)
        {
            if(s[pp]>=10)
            {
                s[pp]%=10;
                if(!pp)
                {
                    ju=1;break;
                }
                s[--pp]++;
                continue;
            }
            break;
        }
        if(ju)printf("1");
        rep(i,0,pos)printf("%c",s[i]+'0');
    }

    B

    给你两个数组a,b。

    让你有多少种取法使得从a中取一个数ai,从b中取一个数bj使得ai+bj是一个质数。

    我是先求出200000内的质数,然后记录b中每个数出现的次数。

    a数组记录个数去重,枚举a。

    int pri[maxn],cnt;
    bool vis[maxn];
    void init()
    {
        for(int i=2;i<maxn;i++)
        {
            if(!vis[i])pri[++cnt]=i;
            for(int j=1;j<=cnt&&pri[j]*i<maxn;j++)
            {
                vis[i*pri[j]]=1;
                if(i%pri[j]==0)break;
            }
        }
    }
    int n,m,a[maxn],b,cntb[maxn],cnta[maxn],ma;
    ll res;
    void solve()
    {
        init();
        sdd(n,m);
        rep(i,1,n)sd(a[i]),cnta[a[i]]++;
        rep(i,1,m)sd(b),cntb[b]++,ma=max(ma,b);
        sort(a+1,a+1+n);
        n=unique(a+1,a+1+n)-a-1;
        rep(i,1,n)
        {
            int k=upper_bound(pri+1,pri+1+cnt,a[i])-pri,sum=0;
            rep(j,k,cnt)
            {
                if(pri[j]-a[i]>ma)break;
                sum+=cntb[pri[j]-a[i]];
            }
            res=res+1ll*cnta[a[i]]*sum;
        }
        plld(res);
    }

    C

    不管a的话题意相当于:有n座山,第i做山的高度为hi,小C只能从当前位置i移动到右边的位置j,且该位置的高度比原位置的高度大。即i<j&&hi<hj,需要花费的体力值为hj*(j-i+1)

    然后有q个询问,每个询问给x,w。x代表起始位置,w代表小C的体力值,问小C能到达的最大位置。

    最开始看错题意(傻

    把hj*(j-i+1)理解成hj*(j-i)

    做法:先预处理,以每个点为起点,求每一个它到能到达的位置需要的体力值。可能会出现当前位置pos到x<y,但是到x的体力值比到y的体力值花费大。so~

    int n,q;
    int a,xx,h[maxn];
    ll x[maxn][maxn];
    vector<PLI >vec[maxn],ans[maxn];
    PII p[maxn];
    int cnt;
    void solve()
    {
        sdd(n,q);
        rep(i,1,n)sdd(a,xx),h[a]=xx;
        rep(i,1,n)//起点
        {
            cnt=0;
            rep(j,i+1,n)//终点
            {
                if(h[j]<=h[i])continue;
                ll mi=1ll*h[j]*(j-i+1);
                rep(k,i+1,j-1)
                {
                    if(h[k]>h[i]&&h[j]>h[k])mi=min(mi,x[i][k]+1ll*h[j]*(j-k+1));
                }
                x[i][j]=mi;
                vec[i].pb(mk(x[i][j],j));
            }
            sort(vec[i].begin(),vec[i].end());
            int si=vec[i].size();
            if(si)ans[i].pb(vec[i][0]);
            rep(j,1,si-1)
            {
                if(vec[i][j].se<ans[i].back().se)continue;
                ans[i].pb(vec[i][j]);//puts("?");
            //  pdd(i,vec[i][j].se);
            }
        }
        while(q--)
        {
            int x,w;
            sdd(x,w);
            int k=upper_bound(ans[x].begin(),ans[x].end(),mk(1ll*w,n+1))-ans[x].begin();
            if(!k)pd(x);
            else pd(ans[x][k-1].se);
        }
    }

    (怎么有点懒得写了orz

    D(不会qwq

    E(水题

    记录质数,然后记录位置是质数的字符,C,S,U出现的次数

    int pri[maxn],cnt;
    bool vis[maxn];
    void init()
    {
        for(int i=2;i<maxn;i++)
        {
            if(!vis[i])pri[++cnt]=i;
            for(int j=1;j<=cnt&&pri[j]*i<maxn;j++)
            {
                vis[i*pri[j]]=1;
                if(i%pri[j]==0)break;
            }
        }
    }
    char str[maxn];
    int c,s,u;
    void solve()
    {
        init();
        sc(str+1);
        int len=strlen(str+1);
        rep(i,2,len)
        {
            if(!vis[i])
            {
                if(str[i]=='S')s++;
                if(str[i]=='C')c++;
                if(str[i]=='U')u++;
            }
        }
        if(c>=2&&s&&u)puts("Yes");
        else puts("No");
    }

    F

    给你一个序列,让你求最长的完美子序列长度

    一个序列是完美的:对于所有的1<=i<n,满足b[i]不是b[i + 1]的因数。

    做法:预处理每个数的因子fac,然后对于第i个数,求前边i-1个数中不是ai的因子且长度最长的长度,我是用线段树做的,找到两个相邻因子中间的数的最大长度。

    vector<int>fac[maxn];
    void init()
    {
        rep(i,1,maxn-5)
        {
            for(int j=1;j*j<=i;j++)
            {
                if(i%j==0)
                {
                    fac[i].pb(j);
                    if(j*j!=i)fac[i].pb(i/j);
                }
            }
            sort(fac[i].begin(),fac[i].end());
        }
    }
    struct node{
        int l,r;
        int ma;
    }a[maxn<<2];
    int n;
    void build(int k,int l,int r)
    {
        a[k].l=l;a[k].r=r;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
    }
    void update(int k,int l,int x)
    {
        if(a[k].l==l&&a[k].r==l)
        {
            a[k].ma=x;
            return;
        }
        int mid=(a[k].l+a[k].r)>>1;
        if(l<=mid)update(k<<1,l,x);
        else update(k<<1|1,l,x);
        a[k].ma=max(a[k<<1].ma,a[k<<1|1].ma);
    }
    int query(int k,int l,int r)
    {
        if(l>r)return 0;
        if(a[k].l>=l&&a[k].r<=r)return a[k].ma;
        int mid=(a[k].l+a[k].r)>>1,ans=0;
        if(l<=mid)ans=query(k<<1,l,r);
        if(r>mid)ans=max(ans,query(k<<1|1,l,r));
        return ans;
    }
    int ans;
    void solve()
    {
        init();
        sd(n);
        build(1,1,1e5);
        rep(i,1,n)
        {
            int x;
            sd(x);
            int si=fac[x].size(),res=0;
            for(int i=0;i<si-1;i++)
            {
                res=max(res,query(1,fac[x][i]+1,fac[x][i+1]-1));
            }
            res=max(res,query(1,x+1,1e5));
            ans=max(ans,res+1);
            update(1,x,res+1);
        }
        pd(ans);
    }

    G

    算出的所有连续子序列中有多少满足:

    1,所有数的和为k的倍数;

    2,且其和至少为z;

    记录前缀和%k的和,然后对于当前位置的sum,满足的是sum-sumi>=z,即sumi<=sum-z,看这个数在vec中的位置

    int n,k,z,a[maxn];
    vector<ll>vec[maxn];
    ll res;
    void solve()
    {
        scanf("%d%d%d",&n,&k,&z);
        rep(i,1,n)sd(a[i]);
    //  rep(i,0,k)vec[i].pb(0);
        vec[0].pb(0);
        ll sum=0;
        rep(i,1,n)
        {
            sum+=a[i];
            int y=sum%k;
            if(sum<z)
            {
                vec[y].pb(sum);
                continue;
            }
            int pos=upper_bound(vec[y].begin(),vec[y].end(),sum-z)-vec[y].begin();
    //      cout<<i<<' '<<y<<' '<<pos<<endl;//' '<<vec[y][pos]<<endl;
            vec[y].pb(sum);
            res+=pos;
        }
        plld(res);
    }

    H

    哈希

    给你两个字符串s和t,问你s中有多少个子串,而这个子串不是t的子串

    (用map和unordered_map都超时了qwq

    const ull base=233;
    int n,m;
    char s[maxn],t[maxn];
    ull p[maxn],has1[maxn],has2[maxn];
    void init()
    {
        p[0]=1;
        rep(i,1,max(n,m))p[i]=p[i-1]*base;
        rep(i,1,n)has1[i]=has1[i-1]*base+s[i];
        rep(i,1,m)has2[i]=has2[i-1]*base+t[i];
    }
    ull get1(int l,int r)
    {
        return has1[r]-has1[l-1]*p[r-l+1];
    }
    ull get2(int l,int r)
    {
        return has2[r]-has2[l-1]*p[r-l+1];
    }
    ull pp[maxn*maxn];
    int res,cnt;
    void solve()
    {
        sdd(n,m);
        sc(s+1);
        sc(t+1);
        init();
        rep(i,1,m)rep(j,i,m)
        {
            pp[++cnt]=get2(i,j);
        }
        sort(pp+1,pp+1+cnt);
        cnt=unique(pp+1,pp+1+cnt)-pp;
        rep(i,1,n)rep(j,i,n)
        {
            ull tmp=get1(i,j);
            int k=lower_bound(pp+1,pp+1+cnt,tmp)-pp;
            if(k>cnt||pp[k]!=tmp)res++;//,pdd(i,j);
        }
        pd(res);
    }

    I

    有一个n*m的矩阵,问你有多少种放法,使得每一行每一列最多只能放置一个

    想法:对于n*m的矩阵,考虑第一行要不要放,放的话有m个位置,答案转移为m*dfs(n-1,m-1),即转化为(n-1)*(m-1)的矩阵的放法。

    不放的话答案转移为dfs(n-1,m),即转化为(n-1)*m的矩阵的方法。

    int n,m;
    int d[maxn][maxn];
    int dfs(int nn,int mm)
    {
        if(nn>mm)swap(nn,mm);
        if(d[nn][mm])return d[nn][mm];
        if(!nn)return 1;
        if(nn==1)return d[nn][mm]=mm+1;
        return d[nn][mm]=(1ll*mm*dfs(nn-1,mm-1)%mod+dfs(nn-1,mm))%mod;
    }
    void solve()
    {
        sdd(n,m);
        pd(dfs(n,m));
    }

    J(不会

    K(不会

    本来没想打的,但是无聊啊!敲了3个小时后就敲不出来了,然后就溜啦~

    欢迎加我qq1165750856一起玩呀~
  • 相关阅读:
    【Luogu1501】Tree(Link-Cut Tree)
    【BZOJ3530】数数(AC自动机,动态规划)
    【BZOJ1212】L语言(AC自动机)
    【BZOJ2037】Sue的小球(动态规划)
    【BZOJ1899】午餐(动态规划)
    【BZOJ1009】GT考试(KMP算法,矩阵快速幂,动态规划)
    【BZOJ1040】骑士(动态规划)
    【BZOJ1969】航线规划(Link-Cut Tree)
    【BZOJ4653】【NOI2016】区间(线段树)
    我也不知道什么是"莫比乌斯反演"和"杜教筛"
  • 原文地址:https://www.cnblogs.com/HHHEN/p/14697689.html
Copyright © 2011-2022 走看看