江西理工大学2023年校赛

文章介绍了几个与算法和数学问题相关的小故事,包括使用迪杰斯特拉算法寻找最短路径,解决数学选择题,判断数字特性,以及在有限资源下优化购买策略和分装问题。还涉及了二分查找和动态规划的运用,并给出了具体的C++和Python代码示例。
摘要由CSDN通过智能技术生成

7-1 我是僵尸

三巷变成了一只僵尸!
他想要杀死村民,可恶的史蒂夫构建了一个无向图并在一些顶点上放置了一些带有标号的陷阱。三巷在变成僵尸之后智商显著降低,他看不见史蒂夫的陷阱,并且只会走最短路径接近村民(不管陷阱),他想要知道他是否能够杀死村民,并且如果被史蒂夫捕获,他是被第几号陷阱捕获的。
三巷总是从1号顶点出发接近处在第n号顶点的村民,顶点的编号总是为1~n,并且可以保证从1到n至多只有一条最短路径并且最少可能1号点与n号点并不连通此时三巷知道自己不可能抓到村民直接用输出NO!(不管会不会被抓住)
注意:如果陷阱在村民所在位置,僵尸也无法伤害到村民而被抓住(史蒂夫太牛了!),并且史蒂夫保护着村民,它可以站在陷阱上!

输入格式:

第 1 行依次为输入为 n,m,k (2≤n≤2000,0≤m≤n2,0≤k≤n) 分别表示顶点数量,边的数量,陷阱数量
第 2 行到第 m+1 行 每行输入 u,v 表示连接 u 与 v 的边
第 m+2 行输入 k 个数字代表第 i 号陷阱处在哪一个顶点上(下标从 1 到 k )

输出格式:

若三巷能够抓住村民则输出YES
如果三巷被陷阱抓获则输出 NO ,并且输出三巷被抓到时中的是第几号陷阱

输入样例1:

4 3 1
1 3
3 4
3 2
2

输出样例1:

YES

输入样例2:

5 5 2
1 3
3 5
1 2
2 4
4 5
2 3

输出样例2:

NO 
2

题解 :用迪杰斯特拉可写,本题因为要输出掉入几号陷阱!,所以用一个path数组记录最短路中所经过的点,其次就是要注意一下可能会不能到达n点,所以一个pd(bool)来判断是否到达n点。

#include<bits/stdc++.h>
#include<string.h>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
    string a;
    int b;
    string c;
};
int n,m,k;
vector<int>a[10000];
int path[10000],dist[10000],dt[10000],pi[10000];
bool pd=false;
void bfs(int t){
    for(int i=1;i<=n;i++){
        dist[i]=0x3f3f3f;
    }
    path[t]=-1;
    queue<int>d;
    d.push(t);
    dist[t]=0;
    dt[t]=1;
    while(!d.empty()){
        int f=d.front();
        d.pop();
        dt[f]=1;
        if(f==n){
            pd=true;break;
        }
        for(auto i:a[f]){
            if(dt[i]==0){
                if(dist[i]>dist[f]+1){
                    dist[i]=dist[f]+1;
                    path[i]=f;
                    d.push(i);
                }
            }
        }
    }
    
}
int main()
{
    cin>>n>>m>>k;
    memset(pi,0,sizeof(pi));
    while(m--){
        int x,y;cin>>x>>y;
        a[x].push_back(y);
        a[y].push_back(x);
    }
    for(int i=1;i<=k;i++){
        int x;cin>>x;
        pi[x]=i;
    }
    bfs(1);
    if(pd){
        int num=n,num1=0;
        while(num!=-1){
            if(pi[num]!=0){
                num1=pi[num];
            }
            num=path[num];
        }
        if(num1==0)cout<<"YES\n";
        else {cout<<"NO\n";cout<<num1<<"\n";}
    }else cout<<"NO\n";
    return 0;
 } 

7-3 盐酸的为爱追寻

(由于小盐小酸互不相让,于是谁也没能追到)自从大觉山森林风景区一别(详情请见盐酸的竞争),小盐和小酸还是对森林少女念念不忘,于是苦苦追寻森林少女的下落,突然有一天,他们发现原来森林少女和他们一样都是江西理工大学的学生。

这次他们向森林少女要微信,但少女想考考他们对江理了解多少,于是丢给他们十个问题,只要他们能把这十个问题都答对,就能要到少女的微信。

但小盐和小酸虽说都是江理的学生,但他们并不太了解江理,于是向你寻求帮助。

*以下题目表述中"答案"均指答案的编号, 即 A/B/C 之一.

输入格式:

第一行输入一个整数n(1<=n<=10)
随后第二行给出n个数字,每个数字代表一个询问,对应每个询问请输出相对应的选择题答案

输出格式:

对应每一个输入给出相对应的答案输出,并间答案之间彼此隔一个空格

输入样例:

3
1 2 3

输出样例:

A C C

本题比较容易:这十题答案分别为ACCCCCCCAB;唯一要注意的点就是 第八题的最大;

#include<bits/stdc++.h>
#include<string.h>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;

int n,m,k;
char a[]={' ','A','C','C','C','C','C','C','C','A','B'};
int main()
{
    cin>>n;
    for(int i=0;i<n;i++){
        int x;cin>>x;
        cout<<a[x]<<" \n"[i==n-1];
    }
    
    return 0;
 } 

7-4 盐酸的竞争

有一天,小盐和小酸去大觉山森林风景区中游玩,在游玩过程中偶遇一位森林少女,于是两人展开疯狂追求,但最后只能被小盐或小酸追得。

于是少女提议,由她随机说出一个数 n,若能被 3 整除或者 n 的每一个数位当中只要含有一个 3 ,则森林少女被小盐追得(输出“xiao yan!”),否则被小酸追得(输出“xiao suan!”)

但是小盐和小酸的数学都不好,想请你帮助求出到底谁会追得该森林少女。

输入格式:

第一行输入为 n (0≤n≤1032),表示该森林少女随机说出的一个数。

输出格式:

只需要输出一行。

如果小盐追得,输出 “xiao yan!”

如果小酸追得,输出 “xiao suan!”

输入样例1:

1

输出样例1:

xiao suan!

输入样例2:

3

输出样例2:

xiao yan!

输入样例3:

34

输出样例3:

xiao yan!

本题不难理解,但是有个小细节,就是数据范围有点大,用c++的话,long long 也会爆;所以要用字符串来写,顺带提醒一下(判断一个数是否是3的倍数,只需要判断该数的每一数位相加是否是3的倍数)。

(本来是应该c++代码,但是由于验题时先用C++验了,然后用Python验,代码被覆盖了,也不想在写了)

n = int(input())
pd = True
t = n
while n :
    d=n%10
    n//=10
    #print(d)
    if d==3 :
        pd=False
        break
if t%3==0 or not pd :
    print("xiao yan!\n")
else :
    print("xiao suan!\n")

7-5 绿松家的点心

众所周知,绿松家的糕点非常好吃。

小巷非常沉迷于绿松家的栗子馒头, 接下来 n 天,他每天都可以去绿松家买一次并且一次只能买一份栗子馒头(可以买也可以不买)。

小巷总共有 m 元,而绿松家的栗子馒头每天早上和晚上的价钱可能是不一样的

他为了去和可爱的看店少女一果酱打招呼,如果他 n 天之中会去购买栗子馒头的话,那么一定要至少一次早上前往绿松家的店铺购买栗子馒头。

小巷想最大化的购买栗子馒头,但是他很懒,于是找到聪明的你帮他计算他最多能买多少栗子馒头。

输入格式:

第一行两个整数 n 和 m,(1≤n≤2×105), (1≤m≤1×109)
第二行 n 个整数 a1​,a2​,...,an​(1≤ai​≤2×109), 代表第 i 天早上栗子馒头的价钱为 ai​。
第三行 n 个整数 b1​,b2​,...,bn​(1≤bi​≤2×109), 代表第 i 天晚上栗子馒头的价钱为 bi​。

输出格式:

输出一个整数,代表小巷最多能买多少栗子馒头。

输入样例1:

2 17
5 8
6 7

输出样例1:

2

输入样例2:

5 6
2 3 4 5 6
6 5 4 3 2

输出样例2:

2

输入样例3:

4 5
5 5 5 5
8 6 4 2

输出样例3:

1

输入样例4:

1 1
2
2

输出样例4:

0

本题二分,由于数据较弱,故可用一些方法冲过去,先排序,再二分他最多能买几天,然后check这答案是否能满足 题意,

#include<bits/stdc++.h>
#include<string.h>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
    ll x,y;
};
ll n,m,k;
bool comp(node x,node y){
    return min(x.x,x.y)<min(y.x,y.y);
}
vector<node>a(1000000);
int path[10000],dist[10000],dt[10000],pi[10000];
bool pd=false;
bool check(int mid){
    bool pd=false;ll sum=0;
    for(int i=1;i<=mid;i++){
        if(a[i].x>a[i].y)sum+=a[i].y;
        else{
            sum+=a[i].x;pd=true;
        }
    }
   
    if(!pd){ 
        ll num=a[mid].x;
        for(int i=mid+1;i<=n;i++){
            if(a[i].x<num){
                num=a[i].x;
            }
        }
        int id=mid;
        
        for(int i=1;i<mid;i++){
            if((a[i].x+a[id].y)<(num+a[i].y)){
                num=a[i].x;
                id=i;
            }
        }
        sum-=a[id].y;
        sum+=num;
    }
    
    if(sum<=m)return true;
    else return false;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){cin>>a[i].x;}
    for(int i=1;i<=n;i++)cin>>a[i].y;
    int l=0,r=n;
    sort(a.begin()+1,a.begin()+n+1,comp);
    while(l<r){
        int mid=l+(r-l+1>>1);
        if(check(mid)){
            l=mid;
        }else{
            r=mid-1;
        }
    }
    cout<<l;
    return 0;
 } 

7-6 Alice的求助

Alice 有 n 种不同颜色的球(用序号 1 到 n 表示,每个序号表示一种颜色)。

同一种颜色的球相互之间无法区分(即颜色相同的球是完全一致的),不同颜色则可以区分。球有很多,可以认为每种颜色的球的数目都是无限的。

此外,还有 m 个盒子(用序号 1 到 m 表示),每个盒子都不同。这就意味着将序号为 1 的球放入第一个盒子但不放入第二个盒子,与将该球放入第二个盒子但不放入第一个盒子是不同的。
Alice 希望按照以下两条规则分装球:

  1. 她不会将同一种颜色的球装在同一个盒子里,所以每个盒子都应该包含不同颜色的球(允许为空);

  2. 对于每种颜色的球,至少应该将一个该颜色的球装进某个盒子里。

Alice 想知道有多少种不同的分装球的方法,但不知道如何计算。

请帮助她并计算这个数字 (答案可能很大,请将答案模上 109+7 后输出) 。

输入格式:

一行包含两个数字 n,m,用空格隔开,分别表示卡片的种类数量,和盒子的数目。

1≤n,m≤1e9

输出格式:

输出模 109+7 后的方案数即可。

输入样例1:

1 3

输出样例1:

7

输入样例2:

1000000000 1000000000

输出样例2:

751201557

本题数学题,因为每个球都可以选择放或者不放进该盒子,有m个盒子,所以应该有2^m的放法,由于球,由于球不能一个盒子都不放,所以情况数要减一,即2^m-1,又因为有n个球,所以不难发现本题答案为((2^m)-1)^n ,最后模上1e9+7;即最后为(((2^m)%mod-1)^n%mod).

N = list(map(int,input().split()))
n = N[0]
m = N[1]
I = 1000000007
print(pow((pow(2,m,I)-1)%I,n,I))

7-6 张炜松学长的烦恼

众所周知,张炜松学长是江西理工出了名的大佬,又帅,学习又好,编程又强,俗称三好学生。因为张炜松学长太优秀啦,导致学妹们疯狂的追求他,
但是他一心只想搞算法。每天下课,张炜松学长都会用最短的时间从教室跑回寝室,如果不能在 t 时间内(包括 t )回到寝室,那么他就会被狂热的学妹包围而无法学算法。
现有一张 n×m 的学校地图,请你帮助张炜松学长1用最短的时间回到寝室。

张炜松可以花费 1 个单位时间走到上下左右 (x,y+1),(x,y−1)(x+1,y),(x−1,y) 中的任意一个,前提为目标点不是墙,且不在学校范围之外。

输入格式:

第一行三个整数 n,m,t (1≤n≤20,1≤m≤20,1≤t≤400) 且 n,m 不同时为 1,分别表示学校地图的行数和列数,和学妹追上他的时间。
随后 n 行 ,每行 m 个字符,代表地图的大小。

∗ 代表这个位置有墙
. 代表这个位置是空地 
Z 代表张炜松学长的位置
Q 代表这个位置是寝室
保证地图只有以上4种字符,并且 Z 和 Q 保证只出现1次。

输出格式:

如果张炜松学长在 t 时间内(包括 t )回到寝室,则第一行输出 "YES",第二行输出张炜松学长所用的最短时间。
如果张炜松学长在 t 时间内没有回到寝室,直接输出 "NO" 即可。

输入样例1:

3 4 5
.Z.*
**.*
.Q.*

输出样例1:

YES
4

输入样例2:

3 4 10
.Z**
*.**
.*Q.

输出样例2:

NO

输入样例3:

3 4 2
.Z.*
.*.*
Q..*

输出样例3:

NO

 本题可以用dfs写,用dfs找到每一条从'Z'到'Q'的路径,选一条用时最短的与t相比,比t小即输出"YES",否则"NO"。

#include<bits/stdc++.h>
#include<string.h>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
    string a;
    int b;
    string c;
};
int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
int n,m,t;
vector<string>a(25);
int ans=0x3f3f3f;
vector<vector<int>>bi(25,vector<int>(25));
void dfs(int x,int y,int dep){
        
        bi[x][y]=1;
        if(a[x][y]=='Q'){
            
            ans=min(dep,ans);
            return;
        }
        for(int i=0;i<4;i++){
            int xx=x+dx[i];
            int yy=y+dy[i];
            if(xx<n&&xx>=0&&yy>=0&&yy<m&&a[xx][yy]!='*'&&!bi[xx][yy]){
                dfs(xx,yy,dep+1);
               bi[xx][yy]=0;
            }
        }
    
}
int main()
{
    cin>>n>>m>>t;
    int x1,y1;
   for(int i=0;i<n;i++){
       cin>>a[i];
       for(int j=0;j<a[i].size();j++){
           if(a[i][j]=='Z'){
               x1=i;y1=j;
           }
       }
   }
    
    dfs(x1,y1,0);
    if(ans<=t){
        cout<<"YES\n";
        cout<<ans<<"\n";
    }
    else cout<<"NO\n";
    
    return 0;
 } 

7-8 打铁的陈末

经过数次打铁,铁匠之神把陈末变成了个小丑🤡。

铁匠之神喜欢研究数学,此时铁匠之神正好碰到了一个经典的数学问题。

问:任意一个正整数最近的与它互质 (两个正整数只有一个公因数1) 的正整数是多少?(如果距离相等则从小到大的输出两个数)。

铁匠之神答应陈末如果解出这道题就让陈末重新做人。

显然陈末还是不会数学,为了让陈末重新做人请你帮帮陈末!

输入格式:

一行一个正整数 N(1≤N≤1×109)  。

输出格式:

输出一个正整数,表示与它互质的数 (如果距离相等则从小到大依次输出两个数)。

输入样例1:

2

输出样例1:

1 3

输入样例2:

1

输出样例2:

2

本题只要仔细看,不难发现一个数n和他相邻的两个数是互质的,即只需输出n-1,n+1,唯一要注意的点即是当n=1时,只输出2.

 

#include<bits/stdc++.h>
#include<string.h>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;

int n,m,k;


int main()
{   //get_prime();
    cin>>n;
    if(n==1)cout<<"2\n";
    else cout<<n-1<<" "<<n+1;
    return 0;
 } 

 

7-9 君士坦丁堡的沦陷

众所周知,君士坦丁堡的城墙坚不可摧,但在1453年,还是没能抵挡住奥斯曼的射石炮,最终沦陷。

现在给你一次改变拜占庭帝国命运的机会,你被安排到战场上帮助拜占庭帝国抵挡奥斯曼的炮弹,假设君士坦丁堡的城墙耐久值为 H,奥斯曼将按顺序发射 N 颗炮弹,每颗炮弹攻击将摧毁城墙耐久度 ai​。

 当城墙的耐久降到(≤)总耐久的 21​ 时炮弹的威力将加倍,为 41​ 时炮弹的威力将再次加倍

你被赋予能在空中让炮弹消失的能力,但是每次只能让一颗炮弹消失

所以,请问你最小需要使用多少次能力才能保卫君士坦丁堡?

输入格式:

第一行两个数整数H(1≤H≤105),N(1≤N≤20),表示城墙耐久值以及炮弹攻击次数。
接下来一行 N 个数 ai​(1≤ai​≤2×104),表示第 i 个炮弹的力量值。

输出格式:

输出一个整数,表示最小需要使用能力的次数。

输入样例1:

1 1 
1

输出样例1:

1

输入样例2:

2 1 
1

输出样例2:

0

本题可以暴力破解,直接枚举每一个炮弹是否使用技能让其消失(也可以是让这枚炮弹是否生效),然后取其中使用技能最小的


#include<bits/stdc++.h>
#include<string.h>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;

int main()
{
    int h,n;
    cin>>h>>n;
    vector<int>a(n);
    for(int i=0;i<n;i++)cin>>a[i];
    int sum=0x3f3f3f; 
    for(int i=0;i<(1<<n);i++){
        int num=h,ans=0;
        for(int j=0;j<n;j++){
            if(i>>j&1){
                if(num>h/2)num-=a[j];
                else if(num>h/4)num-=2*a[j];
                else num-=4*a[j];
            }else ans++;
        }
        if(num>0){
            sum=min(sum,ans);
        }
    }
    cout<<sum;
    return 0 ;
}

 

7-10 百合骑士帮帮我

分数 60

“我要和紫阳花同学交往,我也要和真唯交往!”

在甘织玲奈子说出这样的逆天发言后,玲奈子每天都要和紫阳花和真唯同学的其中一人约会,每次约会后都会获得对应的两个人的好感度。

但因为紫阳花和真唯也是好朋友,两个人都是温柔的人(二人约定不能独占玲奈子),所以当玲奈子与一人约会后,如果第二次约会的是另一个人,那么第二次约会获得的好感度会翻倍,如果前一次约会的好感度为负数那么下一次约会的好感度不会翻倍

玲奈子想要大家都幸福,所以你必须保证紫阳花和真唯都有过至少一次约会

现在玲奈子向你请教,该怎么做才能让获得的总好感度最大

输入格式:

 第一行输入为 t(1≤t≤100) 表示有 t 组输入。

第二行输入为 n(2≤n≤105),两个人可以约会的次数。

第三行输入为 n 个 0 或 1。如果为 1,则为紫阳花的好感度,如果为 0 ,则是真唯的好感度。(确保至少有一个 1 和一个 0 )。

第四行输入为紫阳花和真唯每次约会能获得的好感度 b1​,b2​...bn​ (−109≤bi​≤109)。

输出格式:

输出一行,最大能获得的好感度。

输入样例1:

1
4
0 1 1 1
1 10 100 1000

输出样例1:

2112

0 是真唯的约会机会,好感度为下面的 1,1 是紫阳花的好感度,分别出现了三次说明可以和紫阳花进行三次约会,好感度分别为10 100 1000。
根据题意可以得出最大的好感度为 100+1*2+1000*2+10=2112。

输入样例2:

1
4
0 1 1 1
-1 -10 100 1000

输出样例2:

1099

0 是真唯的约会机会,可以看到好感度为负数,但玲奈子需要和每个人都要约会至少一次,所以就要硬着头皮上。

而 1 是紫阳花的约会机会,但与真唯约会的好感度为负数,所以紫阳花的好感度不会翻倍,那么最大好感度为 -1+100+1000=1099。

 

本题可以将两个人的好感度分开放,并且删除负数,但保留负数中的最大值。若双方中没有为正的好感度,则总的好感度sum+=min2或sum+=min1; 然后是正数则加sum+=sum1+sum2;最后再过一遍翻倍的。

#include<bits/stdc++.h>
#include<string.h>
#include<cmath>
#include<algorithm>
#include<numeric>
#define I 1000000007
using namespace std;
const int MAXN=2e6+5;
const int p=2750131;
typedef long long ll;
int gcd(int a,int b){return (b>0)?gcd(b,a%b):a;}
//计算x和y的最大公约数
int lcm(int x,int y)//计算x和y的最小公倍数
{return x * y / gcd(x, y);}//使用公式
typedef struct node{
	int a,b;
}nodes;
bool  comp(int x,int y){
	return x>y;
}
//排列Cnm;
int zhuhe(int n,int k){
	if(n==k||k==0)return 1;
	else if(k==1)return n;
	else return zhuhe(n-1,k-1)+zhuhe(n-1,k);
}
int n,q;
int a[400020],num1[200010],de[400010];
vector<int>por[200010];
void add(int x,int idx){
    for(auto num:por[x]){
        num1[num]++;
    }
    de[idx]=num1[x];
}
int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);//如果编译开启了 C++11 或更高版本,建议使用 std::cin.tie(nullptr);
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        vector<ll>a(n);
        vector<ll>b,c;
        for(int i=0;i<n;i++)cin>>a[i];
        ll min1=-0x3f3f3f3f,min2=-0x3f3f3f3f;
        ll sum1=0,sum2=0;
        for(int i=0;i<n;i++){
            ll x;cin>>x;
            if(a[i]==0){
                if(x>=0){c.push_back(x);sum1+=x;}
                else {min1=max(min1,x);}
            }
            else{ 
                if(x>=0){b.push_back(x);sum2+=x;}
                else {min2=max(min2,x);}
            }
        }
        sort(c.begin(),c.end());
        sort(b.begin(),b.end());
        ll sum=sum1+sum2;
        if(c.size()==0)sum+=min1;
        if(b.size()==0)sum+=min2;
        if(c.size()==b.size()&&c.size()!=0){
            sum=sum1+sum2-min(c[0],b[0]);
        }
        for(int i=c.size()-1,j=b.size()-1;i>=0&&j>=0;j--,i--){
            sum+=c[i]+b[j];
        }
        cout<<sum<<"\n";    
    }
	return 0;}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值