1. 程式人生 > >【哈爾濱理工大學第七屆程式設計競賽初賽(高年級組)】 A B C D F G H I

【哈爾濱理工大學第七屆程式設計競賽初賽(高年級組)】 A B C D F G H I

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;
}