长沙学院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一起玩呀~
原文地址:https://www.cnblogs.com/HHHEN/p/14697689.html