2018年长沙理工大学第十三届程序设计竞赛 - (A,C,D,E,G,H,J,L)

比赛链接:https://www.nowcoder.com/acm/contest/96#question

ALL

题意:输入一行字符串,如果恰好是lovelive(不区分大小写)就输出yes,否则输出no。

记录下Python代码:

while True:
    try:
        print("yes" if input().lower()=="lovelive" else "no")
    except:
        break
C取手机
题意:有a台iphonex和b台s8,并且放在一个保险箱里,现在一台一台从保险箱随机拿出这些手机,求第k次拿出s8的概率是多少

学的概率都忘了,应该是理解为第几次取对结果是没有影响的,所以可以理解为求第一次取取出s8概率是多少,但是比赛时我算的方法是:先算总共的取法为C(a+b,b),意思就是,理解为有a+b个位置,将a个"1"b个"0"放入这些位置中总共有多少种方案;再求对应k位置为"0",其余位置任意的方案数:C(a+b-1,a),不知道这个方法对不对,倒是得出结果正是b/(a+b)

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T,a,b,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&a,&b,&k);
        cout<<fixed<<setprecision(3)<<(1.0*b/(1.0*a+1.0*b))<<endl;
    }
	return 0;
}
Dzzq的离散数学教室1

题意:对于任意两个正整数a和b(a<b)来说,如果b%a==0,并且不存在一个正整数c(a<c<b),使得条件b%c==0和c%a==0同时成立,那么我们就在节点a和节点b之间连一条边。现在问题是,给你们2个数L,R(1<=L,R<=1e6)。[L,R]中不同两个整数之间组成一个整数对,求有多少整数对满足上面的加边条件。

解析:发现对于[l,r]中一个整数x,满足条件的<x,y>中的y一定是x的素数倍并且小于等于R,那么我们可以先筛素数再统计,然而这里我们枚举[l,r]中每一个数作为x再找有几个y是超时的,可以通过反向思维,枚举每个素数prime[i]判断在它可以作为多少个x的倍数。我才开始是想记录到i为止素数的个数t[i],然后直接遍历for(i=L;i<=R;i++) ans+=t[r/i];但遍历次数太多也超时。

代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
#define M 1000001
int l,r,num,t[M+5];
int prime[M+5];
bool vis[M+5];
void init()
{
    int m=sqrt(M+0.5);
    int i,j;
    num=0;
    for(i=2;i<=m;i++)
    {
        if(!vis[i])
        {
            for(j=i*i;j<=M;j+=i)
            {
                vis[j]=true;
            }
        }
    }
    for(i=2;i<=M;i++)
    {
        if(!vis[i])
        {
            prime[num++]=i;
        }
    }
}

int main()
{
    init();
    while(scanf("%d%d",&l,&r)!=EOF)
    {
        int ans=0;
        for(int i=0;i<num&&prime[i]<=r;i++)
        {
            int t=r/prime[i];     //t是满足x*prime[i]<=r的最大x,[1,t]的所有数都可以作为x去乘prime[i]
            if(t>=l) ans+=(t-l+1);//这里只加[1,t]与[L,R]交集中的x
        }
        printf("%d\n",ans);
    }
	return 0;
}

E小木乃伊到我家
题意:输入两个整数n和m,分别表示有n座城市和m条路,城市编号为1~n(起点城市为1,终点城市为n)。接下来m行,每行输入3个整数u,v,w,分别表示城市u和城市v之间有一条长为w的路。求1到n的最短路径,如果没有路能走到n,则输出“qwb baka”。
解析:最短路径问题

#include<bits/stdc++.h>
using namespace std;
 
const int maxn = 200005;
vector<pair<int,int> >E[maxn];
 
int n,m;
int dis[maxn],vis[maxn];
void init()
{
    for(int i=0;i<maxn;i++) E[i].clear();
    for(int i=0;i<maxn;i++) vis[i] = 0;
    for(int i=0;i<maxn;i++) dis[i] = 1e9;
}
 
int main()
{
    while(cin>>n>>m)
    {
        init();
        for(int i=0;i<m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            E[x].push_back(make_pair(y,z));
            E[y].push_back(make_pair(x,z));
        }
 
        queue<int>Q;
        Q.push(1);
        dis[1] = 0,vis[1] = 1;
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();vis[now] = 0;
            for(int i=0;i<(int)E[now].size();i++)
            {
                int v = E[now][i].first;
                if(dis[v] > dis[now] + E[now][i].second)
                {
                    dis[v] = dis[now] + E[now][i].second;
                    if(vis[v] == 1) continue;
                    vis[v] = 0;
                    Q.push(v);
                }
            }
        }
        if(dis[n] == 1e9) printf("qwb baka\n");
        else printf("%d\n",dis[n]);
    }
}



G逃离迷宫
题意:有一个n*m的图,地图上'.'代表可以走的地方,而'#'代表陷阱不能走,'P'代表人物位置,'K'代表钥匙,'E'代表出口。人物一个,钥匙有多个,('K'的数量<=50)),出口一个,每个位置可以向(上,下,左,右)四个方向走一格,花费一个单位时间,现在你需要花费最少的时间拿到钥匙然后从迷宫的出口出去(若没有钥匙,则不能进入迷宫出口所在的格子)。

解析:先记录每个"K"点信息,用两次bfs,一次求出"P"到所有"K"点的距离,一次求出"E"到所有"K"点的距离,枚举"k"点找最小值,注意两次bfs不同只有在"P"作为起点时不能到"E"和"#",而在"E"作为起点时只是不能为"#"。

代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
#define M 505
#define inf 0x7fffffff
struct node{
    int x,y,s;
};
int n,m,xp,yp,xe,ye;
char mp[M][M];
bool vis[M][M];
node kxy[M];
int ans1[M],ans2[M],numk;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
void bfs1()
{
    queue<node> Q;
    node t1,t2;
    t1.x=xp;
    t1.y=yp;
    t1.s=0;
    Q.push(t1);
    vis[xp][yp]=true;
    while(!Q.empty())
    {
        t1=Q.front();
        Q.pop();
        for(int k=0;k<4;k++)
        {
            t2.x=t1.x+dx[k];
            t2.y=t1.y+dy[k];
            if(t2.x>=0&&t2.x<n&&t2.y>=0&&t2.y<m&&mp[t2.x][t2.y]!='#'&&mp[t2.x][t2.y]!='E'&&vis[t2.x][t2.y]==false)
            {
                vis[t2.x][t2.y]=true;
                t2.s=t1.s+1;
                if(mp[t2.x][t2.y]=='K')
                {
                    //cout<<t2.x<<" "<<t2.y<<endl;
                    for(int r=0;r<numk;r++)
                    {
                        if(kxy[r].x==t2.x&&kxy[r].y==t2.y)
                        {
                            ans1[r]=t2.s;
                            break;
                        }
                    }
                }
                Q.push(t2);
            }
        }
    }
}
void bfs2()
{
    queue<node> Q;
    node t1,t2;
    t1.x=xe;
    t1.y=ye;
    t1.s=0;
    Q.push(t1);
    vis[xe][ye]=true;
    while(!Q.empty())
    {
        t1=Q.front();
        Q.pop();
        for(int k=0;k<4;k++)
        {
            t2.x=t1.x+dx[k];
            t2.y=t1.y+dy[k];
            if(t2.x>=0&&t2.x<n&&t2.y>=0&&t2.y<m&&mp[t2.x][t2.y]!='#'&&vis[t2.x][t2.y]==false)
            {
                vis[t2.x][t2.y]=true;
                t2.s=t1.s+1;
                if(mp[t2.x][t2.y]=='K')
                {
                    //cout<<t2.x<<" "<<t2.y<<endl;
                    for(int r=0;r<numk;r++)
                    {
                        if(kxy[r].x==t2.x&&kxy[r].y==t2.y)
                        {
                            ans2[r]=t2.s;
                            break;
                        }
                    }
                }
                Q.push(t2);
            }
        }
    }
}
int main()
{
    int T,i,j;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        numk=0;
        for(i=0;i<n;i++)
        {
            scanf("%s",mp[i]);
            for(j=0;j<m;j++)
            {
                if(mp[i][j]=='P') {xp=i;yp=j;}
                else if(mp[i][j]=='E') {xe=i;ye=j;}
                else if(mp[i][j]=='K') {kxy[numk].x=i;kxy[numk].y=j;numk++;}
            }
        }
        for(i=0;i<numk;i++)
        {
            ans1[i]=ans2[i]=inf;
        }
        memset(vis,false,sizeof(vis));
        bfs1();

        memset(vis,false,sizeof(vis));
        bfs2();
        int ans=inf;
        for(i=0;i<numk;i++)
        {
            if(ans1[i]!=inf&&ans2[i]!=inf)
            {
                if(ans1[i]+ans2[i]<ans)
                    ans=ans1[i]+ans2[i];
            }
        }
        if(ans!=inf)
            cout<<ans<<endl;
        else
            cout<<"No solution"<<endl;
    }
	return 0;
}

H数学考试

题意:一共有n道题,每道题能获得的分数为ai,但并不打算把这些题全做完,要选总共2*k道题来做,并且期望能获得的分数尽可能的大,准备选2个不连续的长度为k的区间,即[L,L+1,L+2,....,L+k-1],[R,R+1,R+2,...,R+k-1](R >= L+k)。使得这些题目总分和最大。

解析:这道题是优化了好几次才过的,可能是dp但是我dp不怎么样,具体方法见代码

代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
#define M 200005
int n,k,a;
ll sum[M],ans[M],Max[M];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<=n;i++)
        {
            Max[i]=-99999999999999999;
            sum[i]=ans[i]=0;
        }
        cin>>sum[1];
        for(int i=2;i<=n;i++) //sum[i]是前i道题目的分数前缀和
        {
            scanf("%d",&a);
            sum[i]=sum[i-1]+a;
        }
        for(int i=1;i<=n-k+1;i++)//ans[i]是以i为起点的k道题目的分数和,Max[i]是到当前为止最大的一个分数和
        {
            ans[i]=sum[i+k-1]-sum[i-1];
            Max[i]=max(Max[i-1],ans[i]);
        }

        ll res=-99999999999999999;
        for(int i=k+1;i<=n-k+1;i++)
        {
            //cout<<"ans["<<i<<"]="<<ans[i]<<"  "<<"Max["<<i-k<<"]="<<Max[i-k]<<endl;
            res=max(res,ans[i]+Max[i-k]);//(当前段分数和ans[i]+前面段最大的分数和Max[i-k])的最大值即是答案,注意是[i-k]
        }
        cout<<res<<endl;

    }
    return 0;
}


J杯子

题意:有n个球编号1~n,要依次,也就是按照1,2,3...n的顺序放进杯子里,然后在全部拿出来(注意不一定要等到全部放进去才能拿出球),并且会记录放进和拿出球的顺序,想知道,要满足当第m个球进去后,杯子中此时恰好有k个球,然后仍然要把剩下的n-m个球放进去,最后杯中的球要取光,这样的放进和拿出球的顺序有多少种,

解析:很经典的进栈出栈问题,用卡特兰数来解。首先卡特兰数等于C(n+m,n)-C(n+m,m-1),它的一个解释为有有n个"1"、m个"-1"(n>=m),共n+m个数排成一列,满足对所有0<=k<=n+m的前k个数的部分和Sk >= 0的排列数。 问题等价为在一个格点阵列中,从(0,0)点走到(n,m)点且不穿过对角线x==y的方法数(可以走到x==y的点)。(具体见百度百科https://baike.baidu.com/item/%E5%8D%A1%E7%89%B9%E5%85%B0%E6%95%B0/6125746?fr=aladdin)。

对于此题,设入栈为“1”出栈为“-1”,①.对于放置第m个球之前一共有入栈m-1次,出栈m-k次,求进栈大于等于出栈的方案数就是C(m-1+m-k,m-1)-C(m-1+m-k,m-k-1)

②.在放完第m求之后,还需要有入栈n-m次,出栈n-m+k次,这里要求是出栈大于等于进栈的方案数,C(n-m+n-m+k,n-m)-C(n-m+n-m+k,n-m+k-1)

最终答案就是C(m-1+m-k,m-1)-C(m-1+m-k,m-k-1)*C(n-m+n-m+k,n-m)-C(n-m+n-m+k,n-m+k-1)

代码:

#include<bits/stdc++.h>
#define inf 80000000000
#define ll long long
using namespace std;
const int maxn = 1e6+2;
const ll mod = 1e9+7;
ll jie[maxn*2];
int n,m,k,T;
ll pow_mod(ll a,ll b) //快速幂计算(a^b)%mod
{
    ll ret = 1;
    while(b)
    {
        if(b&1) ret = ret%mod*a%mod%mod;
        a = a%mod*a%mod%mod;
        b>>=1;
    }
    return ret;
}
void init()        //计算阶乘
{
    jie[0] = jie[1] = 1;
    for(int i = 1;i<=2*maxn;i++){
        jie[i] = jie[i-1]%mod*i%mod%mod;
    }
}
ll C(ll n,ll m)  //计算C(n,m)
{
    if(m<0) return 0;
    return (jie[n]%mod*pow_mod(jie[n-m]%mod*jie[m]%mod%mod,mod-2)%mod)%mod;//用快速幂求逆元就是将(a/b)%mod换为a*(1/b)%mod,这里(1/b)=pow_mod(b,mod-2)%mod
}
ll Cal(ll n,ll m)  //计算卡特兰数=C(n+m,n)-C(n+m,m-1)
{
    return (C(n+m,n)%mod-C(n+m,m-1)%mod+mod)%mod;
}
int main()
{
    scanf("%d",&T);
    init();
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        if(m<k){
            puts("0");
            continue;
        }
        printf("%lld\n",Cal(n-m+k,n-m)%mod*Cal(m-1,m-k)%mod%mod);
    }
}


L仓鼠养殖计划
题意:有a个架子每个架子可放2个仓鼠,b 个架子每个架子可放1个仓鼠,有n个人,每人a[i]个仓鼠,一个人的不同仓鼠可在同一架子,不同人的仓鼠不可在同一架子,问现有架子能否放下所有仓鼠

代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
#define M 55
int a,b,n,p[M];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&a,&b,&n);
        for(int i=0;i<n;i++)
            scanf("%d",&p[i]);
        bool f=true;
        for(int i=0;i<n;i++)
        {
            while(p[i]>=2)
            {
                if(b>=1)
                {
                    p[i]-=2;
                    b--;
                }else{
                    break;
                }
            }
            while(p[i]>=1)
            {
                if(a>=1)
                {
                    p[i]--;
                    a--;
                }else{
                    break;
                }
            }
            if(p[i])
            {
                f=false;
                break;
            }
        }
        if(f)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值