【哈尔滨理工大学第七届程序设计竞赛初赛(高年级组)】 A B C D F G H I

本文解析了一场算法挑战赛中的多个题目,包括寻找最长递增子序列、计算字符串价值、寻找回文数等,提供了详细的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A 凌波微步
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
小Z的体型实在是太胖了,每次和小D一起出门都跟不上小D的脚步,这让小Z很气馁,于是小Z跋山涉水,仿名山,遍古迹,终于找到了逍遥派。掌门看小Z求师虔诚,决定传小Z一套《凌波微步》。
这种腿法可以无视距离的行进,但缺点是只能走向高处,否则强行发功极易走火入魔。
一天,练习《林波微步》的小Z来到一处练武场,这里从左到右,共有n个木桩,这些木桩有高有低,在这里小Z勤奋的练习着凌波微步,你知道小Z在这处练武场最多能练习多少次么?
输入描述:
本题有T组数据。
对于每组数据第一行有一个正整数n表示有多少个木桩。
第二行有n个数 a_i,表示木桩与水平地面的相对高度。
1≤T≤10
1≤n≤100000
1≤a_i≤1000000000
输出描述:
输出结果,并换行。
示例1
输入

2
6
1 2 3 4 5 6
5
1 3 5 3 6
输出

6
4
分析: 弄清题意啊,LIS wa到死。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 100000+10;
const int MAXM = 1e5;

int arr[MAXN+2];
int main(){
    int n;
    int T ;scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d",&arr[i]);
        sort(arr,arr+n);
        int m=unique(arr,arr+n)-arr;
        printf("%d\n",m);

    }

    return 0;
}

B
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
小Z向女神告白成功,成功脱单,为了庆祝,小Z决定送女神一个礼物。
在珠宝店,小Z终于发现一种既便宜又大气的手链。
手链的价格是看手链上的宝石决定的,每一种宝石的价值不一样。
具体规则如下:
宝石A的价值是1、宝石B的价值是2、宝石C的价值是3·····宝石Z的价值是26。
为了防止被销售员虚报价格,小Z决定请你帮忙计算一下手链的价值。
输入描述:
本题有T组数据。
对于每组数据只有一行。
1≤T≤20
1≤手链长度≤100000
输出描述:
输出结果,并换行。
示例1
输入

2
ABCD
LOVELOVE
输出

10
108

//package FirstTime;
import java.util.*;
import java.math.*;
import java.text.DecimalFormat;

public class Main{

    public static void main(String[] agrs){
         Scanner cin = new Scanner(System.in);
         String t=cin.next();
         while(cin.hasNext()){
             String s=cin.next();
             int len=s.length();
             int ans=0;
             for(int i=0;i<len;i++) 
                 ans+=s.charAt(i)-'A'+1;
             System.out.println(ans);
         }

    }
}

C
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
今天是Tabris和mengxiang000来到幼儿园的第6天,美丽的老师在黑板上写了几个数字:121,11,131,聪明的Tabris一眼就看出这些数字是那样的神奇——无论是正着写还是反着写都是一样的,mengxiang000想要得到更多的这样有趣的数,又因为这是二人到幼儿园的第6天,6+2=8。他们想知道长度为8的这样的数都有哪些。但是写着写着机智的Tabris发现这样神奇的数实在太多了,所以向你求助,你能帮帮他们吗?
输入描述:

输出描述:
从小到大输出所有符合题意的数,每个数占一行。
示例1
输入

none
输出

none

//package FirstTime;
import java.util.*;
import java.math.*;
import java.text.DecimalFormat;

public class Main{
     static void f(int j){
         String s=""+j;
         for(int i=s.length()-1;i>=0;i--) System.out.print(s.charAt(i));
     }
    public static void main(String[] agrs){
         Scanner cin = new Scanner(System.in);
          for(int i=1000;i<=9999;i++) {
              System.out.print(i);f(i);
              System.out.println();
          }
    }
}

D 经商
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
小d是一个搞房地产的土豪。每个人经商都有每个人经商的手段,当然人际关系是需要放在首位的。
小d每一个月都需要列出来一个人际关系表,表示他们搞房地产的人的一个人际关系网,但是他的精力有限,对应他只能和能够接触到的人交际。比如1认识2,2认识3,那么1就可以接触3进行交际,当然1和2也可以交际。
小d还很精明,他知道他和谁交际的深获得的利益大,接下来他根据自己的想法又列出来一个利益表,表示他和这些人交际需要耗用多少精力,能够获得的利益值为多少。
小d想知道,他在精力范围内,能够获得的利益值到底是多少。
设定小d自己的编号为1.并且对应一个人的交际次数限定为1.
输入描述:
本题包含多组输入,第一行输入一个数t,表示测试数据的组数
每组数据的第一行输入三个数,N,M,C,表示这个人际关系网一共有多少个人,关系网的关系数,以及小d的精力值
接下来N-1行,每行两个数ai,bi。这里第i行表示和编号为i+1的人认识需要花费ai的精力,能够获得的利益值为bi。
再接下来M行,每行两个数x,y,表示编号为x的人能够和编号为y的人接触
t<=50
2<=N<=10000
1<=M<=10*N
1<=ai,bi<=10
1<=C<=500
1<=x,y<=N
输出描述:
输出包含一行,表示小d能够获得的最大利益值
示例1
输入

1
5 3 7
5 10
3 2
4 3
1 100
1 2
2 3
1 4
输出

10
分析: 并查集+背包
代码

//package FirstTime;
import java.util.*;
import java.math.*;
import java.text.DecimalFormat;

public class Main{
    static final int MAXN = 10000+11;
    static final int MAXM = 100000+11;

    static int[] pre=new int[MAXN];
    static void init(int n) { for(int i=0;i<=n;i++) pre[i]=i; }
    static int Find(int x){ return x==pre[x]?x:(pre[x]=Find(pre[x])); }

    public static void main(String[] agrs){
        int[] cost=new int[MAXN];  int[] val =new int[MAXN];
        int[] x   =new int[MAXM];  int[] y   =new int [MAXM];
        int[] aa  =new int[MAXN];  int[] bb  =new int[MAXN];

         Scanner cin = new Scanner(System.in);
          int t ;t=cin.nextInt();
          while(t-->0){
              int[][] dp= new int[10000+11][500+11];// 自带清空
              int n,m,c; n=cin.nextInt(); m=cin.nextInt(); c=cin.nextInt();
              init(n);
              for(int i=1;i<n;i++)  { aa[i]=cin.nextInt(); bb[i]=cin.nextInt(); }
              for(int i=1;i<=m;i++) { x[i]=cin.nextInt();  y[i]=cin.nextInt();  }

              for(int i=1;i<=m;i++){
                  int a,b; a=x[i]; b=y[i];
                  a=Find(a);  b=Find(b);
                  if(a!=b) pre[a]=b;
              }
              int id=0;
              for(int i=1;i<n;i++){
                  int a,b; a=aa[i]; b=bb[i];
                  if(Find(i+1)==Find(1)){
                      cost[++id]=a; val[id]=b;
                  }
              }
              for(int i=id;i>=1;i--){
                  for(int j=0;j<=c;j++){
                      if(j<cost[i]) dp[i][j]=dp[i+1][j];
                      else 
                      dp[i][j]=Math.max(dp[i+1][j],dp[i+1][j-cost[i]]+val[i]);
                  } 
              }
              System.out.println(dp[1][c]);
          }
    }
}

F 苦逼的单身狗
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
双11又到了,小Z依然只是一只单身狗,对此他是如此的苦恼又无可奈何。
为了在这一天脱单小Z决定向女神表白,但性格腼腆的小Z决定隐晦一点,截取一段包含’L’、’O’、’V’、’E’的英文。(顺序不限)
小Z想起之前小D送给他一本英文书,决定在这里面截取一段话,小Z发现有好多种方案来截取这段话。
你能知道小Z能有多少种方案截取这段话么?
为了简化问题,英文文本讲不会出现空格、换行、标点符号及只有大写的情况。
输入描述:
本题有T组数据。
对于每组数据只有一行文本。
1≤T≤20
1≤文本长度≤100000
输出描述:
输出结果,并换行。
示例1
输入

3
ILOVEACM
LOVELOVE
ALBECVOD
输出

8
15
4
分析:对维护连续子序列的某种特点的时候,可以考虑尺取法 。

#include<bits/stdc++.h>
using namespace std;
#define LL long long

const int MAXN = 100000+11 ;
const int MAXM = 1e3 +11;
const int inf = 0x3f3f3f3f;

char s[MAXN+2];
map<char,int>cnt;
int main(){
    int  T;scanf("%d",&T);
    while(T--){
        cnt.clear();
        scanf("%s",s);int len=strlen(s);
        int st,ed; st=ed=0; LL ans=0; int num=0;
        for(;;){
            while(ed<len&&num<4){
                if(s[ed]=='L'||s[ed]=='E'||s[ed]=='V'||s[ed]=='O') {
                    cnt[s[ed]]++;
                    if(cnt[s[ed]]==1) num++;;
                }
                ed++;
            }
            if(num<4) break;
            //printf("ed %d \n",ed);
            ans+=len-ed+1;
             if(s[st]=='L'||s[st]=='E'||s[st]=='V'||s[st]=='O') {
                cnt[s[st]]--;
                if(cnt[s[st]]==0) num--;
             }
             st++;
            // printf("st %d \n",st);
        }
        printf("%lld\n",ans);
    }
return 0;
}

G 逃脱
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
这是mengxiang000和Tabris来到幼儿园的第四天,幼儿园老师在值班的时候突然发现幼儿园某处发生火灾,而且火势蔓延极快,老师在第一时间就发出了警报,位于幼儿园某处的mengxiang000和Tabris听到了火灾警报声的同时拔腿就跑,不知道两人是否能够逃脱险境?
幼儿园可以看成是一个N*M的图,在图中一共包含以下几种元素:
“.”:表示这是一块空地,是可以随意穿梭的。
“#”:表示这是一块墙,是不可以走到这上边来的,但是可以被火烧毁。
“S”:表示mengxiang000和Tabris所在位子。
“E”:表示幼儿园的出口。
“*”表示火灾发源地(保证输入只有一个火灾发源地)。
已知每秒有火的地方都会向周围八个格子(上下左右、左上、右上、左下、右下)蔓延火势.mengxiang000和Tabris每秒都可以选择周围四个格子(上下左右)进行移动。(假设两人这一秒行动完之后,火势才蔓延开)
根据已知条件,判断两人能否成功逃脱险境,如果可以,输出最短逃离时间,否则输出T_T。
为了防止孩子们嬉戏中受伤,墙体是橡胶制作的,可以燃烧的哦。
输入描述:
第一行输入一个整数t,表示一共的测试数据组数。
第二行输入两个整数n,m,表示幼儿园的大小。
接下来n行,每行m个字符,表示此格子是什么元素。
t<=200
3<=n<=30
3<=M<=30
保证图中有一个起点,一个出口,一个火灾源处
输出描述:
每组数据输出一行,如果两人能够成功到达出口,那么输出最短逃离时间,否则输出T_T
示例1
输入

3
5 5
*….
…..
..S#.
…E.
…..
5 5
…#*
..#S#
…##
….E
…..
5 5
…..
S….
..*#.
…E.
…..
输出

2
T_T
T_T
说明

为了防止孩子们嬉戏中受伤,墙体是橡胶制作的,可以燃烧的哦。
备注:
为了防止孩子们嬉戏中受伤,墙体是橡胶制作的,可以燃烧的哦

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 50+11;
const int inf = 0x3f3f3f3f;

struct Node{
    int x,y,step;
};
int n,m;
int mp[MAXN+2][MAXN+2];
int Time[MAXN+2][MAXN+2];
bool vis[MAXN+2][MAXN+2];
int to[8][2]={1,0,-1,0,0,1,0,-1,-1,-1,-1,1,1,-1,1,1};

void Getfire(Node fire){
    memset(Time,-1,sizeof(Time));
    queue<Node>Q;
    Q.push(fire); Time[fire.x][fire.y]=0;
    while(!Q.empty()){
        Node now = Q.front(); Q.pop();
        for(int i=0;i<8;i++){
            int nx=now.x+to[i][0]; int ny=now.y+to[i][1];
            if(nx<1||nx>n||ny<1||ny>m) continue;
            if(Time[nx][ny]!=-1) continue;
            Time[nx][ny]=now.step+1;
            Node next={nx,ny,now.step+1};
            Q.push(next);
        }
    }
   /* for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            printf("%d",Time[i][j]);
        puts("");
    }
    */
}
void BFS(Node s){
   // for(int i=0;i<4;i++)  printf("%d %d \n",to[i][0],to[i][1]);
    memset(vis,0,sizeof(vis));
    queue<Node>Q; Q.push(s); vis[s.x][s.y]=1;
    while(!Q.empty()){
        Node now=Q.front(); Q.pop() ;
        for(int i=0;i<4;i++){
            int nx=now.x+to[i][0]; int ny=now.y+to[i][1];
            if(nx<1||nx>n||ny<1||ny>m) continue;
            if(vis[nx][ny]||mp[nx][ny]==2) continue;

            if(now.step+1<=Time[nx][ny]&&mp[nx][ny]==3)  {
                printf("%d\n",now.step+1);
                return ; //如果跑到出口的时间正好和着火时间一样,那样这个人也可以逃脱
            }

            if(now.step+1>=Time[nx][ny]) continue;//但是如果是一个普通地区,到达时间和着火时间一样,肯定GG。
            Node next={nx,ny,now.step+1};
            vis[nx][ny]=1;
            Q.push(next);
        }
    }
    puts("T_T");
}
char s[100];
int main(){
    int tt;scanf("%d",&tt);
    while(tt--){
        memset(mp,0,sizeof(mp));
        scanf("%d%d",&n,&m);
        Node st,fire;
        for(int i=1;i<=n;i++){
           scanf("%s",s); int len=strlen(s);
            for(int j=0;j<len;j++) {
                if(s[j]=='.') mp[i][j+1]=1;
                else if(s[j]=='#') mp[i][j+1]=2;
                else if(s[j]=='S'){
                    mp[i][j+1]=1;
                    st={i,j+1,0};
                }
                else if(s[j]=='E') mp[i][j+1]=3;
                else if(s[j]=='*')  {
                    mp[i][j+1]=4;
                    fire={i,j+1,0};
                }
            }
        }
        /*
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
            printf("%d",mp[i][j]);
            puts("");
        } */
        Getfire(fire);
        BFS(st);
    }
return 0;
}

H 布置会场(II)
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
小d接到了一个布置会场的任务。
他需要将贵宾观众席的椅子排成一排,一共需要N个。
上级领导指示,他只能使用两种椅子。(A类型和B类型)并且假设每种椅子的数量都是无限的。
而其如果想要摆置一个B类型的椅子,对应就需要必须有连续两个一起布置。换句话说,就是如果出现了B类型的椅子,其必须且只有两个连着B类型的椅子。
小d突然想知道对应N个椅子排成一列,他能够有多少种布置的方式.
输入描述:
本题包含多组输入第一行输入一个整数t,表示测试数据的组数
每组测试数据包含一行,输入一个整数N,表示一共需要摆放的椅子数量
t<=1000
1<=N<=100000000000000000(10^18)
输出描述:
每组测试数据输出包含一行,表示一共有多少种布置的方式,方案数可能会很大,输出对1000000007取摸的结果。
示例1
输入

2
2
4
输出

2
5
说明

第一个样例,AA,BB两种方案。
第二个样例,AAAA,BBBB,AABB,ABBA,BBAA五种方案 对于ABBB 因为有连续3个B类型椅子所以不可行

分析:找出前几项,就会发现是一个斐波那契数列,然后矩阵快速幂就行。
代码

#include<bits/stdc++.h>
using namespace std ;
typedef long long LL ;

const int MAXN = 100000+10;
const int MAXM = 1e5 ;
const LL mod  =  1000000007;
const int  inf = 0x3f3f3f3f; 

struct Matirx {
    int h,w;
    LL a[5][5];
}ori,res,it;
LL f[5]={0,1,1};
void init(){
    it.w=2;it.h=1;it.a[1][1]=1;it.a[1][2]=0;
    res.w=res.h=2;
    memset(res.a,0,sizeof(res.a));
    res.a[1][1]=res.a[2][2]=1;
    ori.w=ori.h=2;
    memset(ori.a,0,sizeof(ori.a));
    ori.a[1][1]= 1;ori.a[1][2]= 1;
    ori.a[2][1]= 1;ori.a[2][2]= 0;  
}
Matirx multy(Matirx x,Matirx y){
    Matirx z;z.w=y.w;z.h=x.h;
    memset(z.a,0,sizeof(z.a));
    for(int i=1;i<=x.h;i++){
        for(int k=1;k<=x.w;k++){
            if(x.a[i][k]==0) continue;
            for(int j=1;j<=y.w;j++)
                z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
        }
    }
    return z;
}

LL Matirx_mod(LL n){
    if(n<2) return f[n];
    else n-=1;
    while(n){
        if(n&1) res=multy(ori,res);
        ori=multy(ori,ori);
        n>>=1;
    }
    res=multy(it,res);
    return res.a[1][1]%mod;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
      LL k;  
       scanf("%lld",&k);
       init(); 
       printf("%lld\n",Matirx_mod(k+1)%mod); 
     }
    return 0;
}

I B-旅行
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述

小z放假了,准备到RRR城市旅行,其中这个城市有N个旅游景点。小z时间有限,只能在三个旅行景点进行游玩。小明租了辆车,司机很善良,说咱不计路程,只要你一次性缴费足够,我就带你走遍RRR城。

小z很开心,直接就把钱一次性缴足了。然而小z心机很重,他想选择的路程尽量长。

然而司机也很聪明,他每次从一个点走到另外一个点的时候都走最短路径。

你能帮帮小z吗?

需要保证这三个旅行景点一个作为起点,一个作为中转点一个作为终点。(一共三个景点,并且需要保证这三个景点不能重复).
输入描述:
本题包含多组输入,第一行输入一个整数t,表示测试数据的组数
每组测试数据第一行输入两个数N,M表示RRR城一共有的旅游景点的数量,以及RRR城中有的路的数量。
接下来M行,每行三个数,a,b,c表示从a景点和b景点之间有一条长为c的路
t<=40
3<=N,M<=1000
1<=a,b<=N
1<=c<=100
输出描述:
每组数据输出两行,
每组数据包含一行,输出一个数,表示整条路程的路长。
如果找不到可行解,输出-1.
示例1
输入

4
7 7
1 2 100
2 3 100
1 4 4
4 5 6
5 6 10
1 6 4
6 7 8
7 3
1 2 1
1 3 1
1 3 2
7 3
1 2 1
3 4 1
5 6 1
8 9
1 2 1
2 3 1
3 4 1
4 1 1
4 5 1
5 6 1
6 7 1
7 8 1
8 5 1
输出

422
3
-1
9
分析: 分析题意之后,第一反应就是,我们可以枚举三点的中间点,然后求最短路,然后找到这些最短路中的两个最长路径。 什么最短路算法可以做到0(n)呢? 然后突然想到spfa可以哎,这里n==e,而spfa 平均情况下就是ke,估计要卡时间。 没想过可以过。

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 1e3+11 ;
const int MAXM = 1e3 +11;
const int inf = 0x3f3f3f3f;

struct Edge {
    int from,to,val,next;
}edge[MAXM*3];
int head[MAXN],top;
void init(){
    memset(head,-1,sizeof(head));
    top=0;
}
void addedge(int a,int b,int c){
    Edge e={a,b,c,head[a]};
    edge[top]=e;head[a]=top++;
}
int n,m;
void getmap(){
    while(m--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        addedge(a,b,c);
        addedge(b,a,c);
    }
}

int dis[MAXN],vis[MAXN];
int spfa(int st){
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    queue<int>Q;
    Q.push(st); dis[st]=0; vis[st]=1;
    while(!Q.empty()){
        int now=Q.front();Q.pop();vis[now]=0;
        for(int i=head[now];i!=-1;i=edge[i].next){
            Edge e =edge[i]; //puts("===");
            if(dis[e.to]>dis[now]+e.val){
                dis[e.to]=dis[now]+e.val;
                if(!vis[e.to]){
                    Q.push(e.to);
                    vis[e.to]=1;
                }
            }
        }
    }

    int ans=0;int a=-1,b=-1;int x=0,y=0; // 获得两个最大路径
    for(int i=1;i<=n;i++){
        if(dis[i]==inf||i==st) continue;
        if(dis[i]>x){
            x=dis[i];
            a=i;
        }
    }
    if(a==-1) return -1;
    for(int i=1;i<=n;i++){
        if(dis[i]==inf||i==st||i==a)continue;
        if(dis[i]>y){
            y=dis[i];
            b=i;
        }
    }
    if(b==-1) return -1;
    return dis[a]+dis[b];
}

int main(){
    int T ;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init();
        getmap();
        int ans=-1;
        for(int i=1;i<=n;i++)
            ans=max(ans,spfa(i));
        printf("%d\n",ans);
    }

return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值