大慶市中學生計算機技術應用能力大賽

weixin_30639719發表於2020-04-05

emmmmm雖然分還沒出就瞎幾把寫一寫蒟蒻的思路


第一題:遭遇戰


【問題描述】
小林和小華在一個 n×n 的矩形方格里玩遊戲,矩形左上角為(0,0),右下角為(n-1,n-1)。
兩人同時進入地圖的隨機位置,並以相同速度進行走位。為了隱蔽性,兩人都不會再走自己走過的格子。如果兩人向某一方向前進,那麼他們會跑到不能跑為止,當不能跑的時候,小林會向右轉,小華則會向左轉,如果不能跑,則不再動。現在已知兩人進入地圖的初始位置和方向,請算出兩人遭遇的位置。
【輸入格式】
第 1 行 1 個正整數 t,表示測試資料組數,$1≤t≤10$。
接下來的 t 組資料,每組資料的第 1 行包含 1 個整數 n,$1≤n≤1000$。
第 2 行包含 3 個整數 x、y 和 d,表示小林的初始位置和一開始跑的方向。其中,d=0 表示東; d=1 表示南;d=2 表示西;d=3 表示北。
第 3 行與第 2 行格式相同,但描述的是小華。


【輸出格式】
輸出 t 行,若會遭遇,則包含兩個整數,表示他們第一次相遇格子的座標,否則輸出“-1”。


【輸入樣例】
2
2
0 0 0
0 1 2
4
0 1 0
3 2 0


【輸出樣例】
-1
1 3


蒟蒻只想出了爆搜。。。貼程式碼


#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1010
using namespace std;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};//方向
int t,n,x,y,d,x1,y1,d1;
bool a[maxn][maxn],b[maxn][maxn];//記錄小林和小華走過的地方
void dfs()
{
    bool f1=true,f2=true;
    while((x!=x1)||(y!=y1)){//搜到兩人相遇或走不了了
        if(f1){//小林還能走
            int j=x+dx[d],k=y+dy[d];//移動
            if(!a[j][k]){//沒走過
                d=(d+1)%4;
                j=x+dx[d];
                k=y+dy[d];//走
                if(!a[j][k]){//打標記
                    f1=false;
                }
            }
            if(f1){//小林還能走
                x=j;
                y=k;
                a[j][k]=false;//打標記
            }
        }
        if(f2){//小華還能走同小林
            int j=x1+dx[d1],k=y1+dy[d1];
            if(!b[j][k]){
                d1=(d+3)%4;
                j=x1+dx[d1];
                k=y1+dy[d1];
                if(!b[j][k]){
                    f2=false;
                }
            }
            if(f2){
                x1=j;
                y1=k;
                b[j][k]=false;
            }
        }
        if((!f1)&&(!f2)){
            break;
        }
    }
    if((x==x1)&&(y==y1)){//相遇了
        printf("%d %d\n",x,y);
    }
    else{//沒相遇
        printf("-1\n");
    }
    return;
}
int main()
{
    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        scanf("%d",&n);
        scanf("%d%d%d%d%d%d",&x,&y,&d,&x1,&y1,&d1);
        memset(a,false,sizeof(a));
        memset(b,false,sizeof(b));
        for(int j=0;j<n;j++){
            for(int k=0;k<n;k++){
                a[j][k]=true;
                b[j][k]=true;//初始化
            }
        }
        dfs();
    }
    return 0;
}

是真的暴力,,,手動滑稽


第二題 保齡球


【問題描述】
打保齡球是用一個滾球去打擊十個站立的柱,將柱擊倒。一局分十輪,每輪可滾球一次或多次,以擊倒的柱數為依據計分。一局得分為十輪得分之和,而每輪的得分不僅與本輪滾球情況有關,還可能與後續一兩輪的滾球情況有關。即某輪某次滾球擊倒的柱數不僅要計入本輪得分,還可能會計入前一兩輪得分。具體的滾球擊柱規則和計分方法如下:

(1) 若某一輪的第一次滾球就擊倒全部十個柱,則本輪不再滾球(若是第十輪則還需另加兩次滾球,不妨稱其為第十一輪和第十二輪,並不是所有的情況都需要滾第十一輪和第十二輪球)。該輪得分為本次擊倒柱數 10 與以後兩次滾球所擊倒柱數之和。
( 2) 若某一輪的第一次滾球未擊倒十個柱,則可對剩下未倒的柱再滾球一次。如果這兩次滾球擊倒全部十個柱,則本輪不再滾球(若是第十輪則還需另加一次滾球),該輪得分為這兩次共擊倒柱數 10 與以後一次滾球所擊倒柱數之和。

(3) 若某一輪兩次滾球未擊倒全部十個柱,則本輪不再繼續滾球,該輪得分為這兩次滾球擊倒的柱數之和。
總之,若某一輪中一次滾球或兩次滾球擊倒十個柱,則本輪得分是本輪首次滾球開始的連續三次滾球擊倒柱數之和(其中有一次或兩次不是本輪滾球)。若一輪內二次滾球擊倒柱數不足十個,則本輪得分即為這兩次擊倒柱數之和。下面以例項說明如下:
輪 1 2 3 4 5 6 7 8 9 10 11 12
擊球情況 / / / 72 9/ 81 8/ / 9/ / 8/
各輪得分 30 27 19 9 18 9 20 20 20 20
累計總分 30 57 76 85 103 112 132 152 172 192
現在請編寫一個保齡球計分程式,用來計算並輸出最後的總得分。


【輸入格式】
輸入一行,為前若干輪滾球的情況,每輪滾球用一到兩個字元表示,每一個字元表示一次擊球,字元“/”表示擊倒當前球道上的全部的柱,否則用一個數字字元表示本次滾球擊倒的當前球道上的柱的數目,兩輪滾球之間用一個空格隔開。


【輸出格式】
輸出一行一個整數,代表最後的得分。


【輸入樣例 1】
/ / / 72 9/ 81 8/ / 9/ / 8/


【輸出樣例 1】
192


【輸入樣例 2】
90 90 / 9/ 81 / / / 72 / /0


【輸出樣例 2】
170


【輸入樣例 3】
/ / / 72 9/ 81 8/ / 9/ 15


【輸出樣例 3】
169


這題。。。不會打保齡球。。。直接模擬。。。貼程式碼


#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define maxn 100
using namespace std;
int main()
{
    //freopen("read.txt","r",stdin);
    char c,st[maxn];
    int ans=0,cur=0,cnt=0;
    while(~scanf("%c",&c)){//毒瘤輸入
        if(c!=' '){
            st[++cur]=c;//只要有用的
        }
    }
    for(int i=1,j=1;i<=10;i++){//很一般的模擬
        if(st[j]=='/'){
           cnt=10;
           if(st[j+1]=='/'){
                cnt+=10;
                if(st[j+2]=='/'){
                    cnt+=10;
                }
                else{
                    cnt+=st[j+2]-'0';
                }
            }
            else{
                if(st[j+2]=='/'){
                    cnt+=10;
                }
                else{
                    cnt+=st[j+1]-'0'+st[j+2]-'0';
                }
            }
            j+=1;
        }
        else{
            if(st[j+1]=='/'){
                if(st[j+2]=='/'){
                    cnt=20;
                }
                else{
                    cnt=10+st[j+2]-'0';
                }
            }
            else{
                cnt=st[j]-'0'+st[j+1]-'0';
            }
            j+=2;
        }
        ans+=cnt;
    }
    printf("%d\n",ans);
    return 0;
}

你看就非常的暴力


第三題 同花順


題目描述
所謂同花順,就是指一些撲克牌,它們花色相同,並且數字連續。
現在我手裡有n 張撲克牌,但它們可能並不能湊成同花順。我現在想知道,最
少更換其中的多少張牌,我能讓這n 張牌湊成一個同花順?


輸入格式
第一行一個整數n,表示撲克牌的張數。
接下來n 行,每行兩個整數$a_i$ 和$b_i$。其中$a_i$ 表示第i 張牌的花色,$b_i$ 表示第
i 張牌的數字。
(注意:這裡的牌上的數字不像真實的撲克牌一樣是1 到13,具體見資料範圍)


輸出格式
一行一個整數,表示最少更換多少張牌可以達到目標。


樣例輸入1
5
1 1
1 2
1 3
1 4
1 5


樣例輸出1
0


樣例輸入2
5
1 9
1 10
2 11
2 12
2 13


樣例輸出2
2


資料範圍
對於30% 的資料,n ≤ 10。
對於60% 的資料,$n ≤ 10^5,1 ≤ a_i ≤ 10^5,1 ≤ b_i ≤ n$。
對於100% 的資料,$n ≤ 10^5$,$1 ≤ a_i, bi ≤ 10^9$。


找一段同花上升子序列。。。貼程式碼


#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,ans,cnt;//最長序列長度,計數器
struct node{
    int col,num;//花色大小
}a[100010],q[100010];
int cmp(node x,node y){//按花色和大小排順序
    if(x.col==y.col){
        return x.num<y.num;
    }
    return x.col<y.col;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].col,&a[i].num);
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        if(a[i].col==a[i-1].col&&a[i].num==a[i-1].num){
            continue;
        }
        q[++cnt]=a[i];
    }
    for(int i=1;i<=cnt;i++){
        int tmp=0;
        for(int j=i;j>=1;j--){
            if((q[j].col==q[i].col)&&(q[i].num-q[j].num+1<=n)){
                tmp++;//去重
            }
            else break;
        }
        ans=max(ans,tmp);
    }
    printf("%d",n-ans);
    return 0;
}

第四題 拯救世界


題目描述
C 城所有的道路都是單向的。不同道路之間有路口,每個路口都有一個大樓。有一天,城市裡的所有大樓因為不明原因,突然著火了。作為超人的你要去拯救
這些大樓。初始的時候你在S 號樓,最後你必須到達某個有補給站的大樓,你可以
沿著單向道路行駛。你可以經過某條道路或者某個大樓若干次,經過一個大樓你就
可以消滅一個大樓的大火。每個大樓都有一個重要程度,最後這個任務的評價分數
就是你經過的所有大樓的重要度之和(若重複經過某個大樓多次,則不重複算分)。
你是一個聰明的超人,你想知道,通過合理的規劃路線,你這次任務能得到的
最高得分是多少。
注意,該城市的道路可能有重邊或自環。


輸入格式
第一行包括兩個整數n,m,n 表示路口的個數(即大樓的個數),m 表示道路
的條數。
接下來m 行,每行兩個整數x; y,表示x 到y 之間有一條單向道路。
接下來n 行,每行一個整數,按順序表示每個大樓的重要度。
接下來一行包含兩個整數S 和P,S 是出發的路口(大樓)的編號,P 是有補
給站的大樓的數量。
接下來一行P 個整數,表示有補給站的大樓的編號。


輸出格式
輸出一行一個整數,表示你得分的最大值。


樣例輸入1
6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1
5
1 4
4 3 5 6


樣例輸出1
47


資料範圍
對於1、2、3 測試點,N;M ≤ 300
對於4、5、6、7、8、9、10 測試點,N;M≤ 3000
對於11、12、13、14、15 測試點,N;M ≤ 500000。每個大樓的重要度均為非
負數且不超過4000。
輸入資料保證你可以從起點沿著單向道路到達其中的至少一個有補給站的大
樓。
注意,輸入資料中存在樹和鏈的特殊情況


終於沒有暴力的最後一題。。。太監縮點+最短路(SPFA考試時忘了所以用的dfs估計要超時)
程式碼碼住


#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500050
using namespace std;
int n,m,num,head[maxn],head1[maxn],w[maxn],t[maxn],s,cur,w1[maxn];
int ans=0;
struct node{
    int to,pre;
}e[maxn],e1[maxn];//鄰接表
void ins(int from,int to){//加邊
    e[++num].to=to;
    e[num].pre=head[from];
    head[from]=num;
}
int dfn[maxn],low[maxn],st[maxn],bel[maxn];
bool instr[maxn];
int nums,cnt,numtj;
void tarjan(int u){//太監縮點,因為一個強連通分量內所有的點都能到達,所以當一個處理
    cnt++;
    st[++nums]=u;
    dfn[u]=low[u]=cnt;
    instr[u]=1;
    for(int i=head[u];i;i=e[i].pre){
        int v=e[i].to;
        if(!dfn[v]){
            tarjan(v);
            if(low[v]<low[u]){
                low[u]=low[v];
            }
        }
        else if(dfn[v]<low[u])
            if(instr[v])
            low[u]=dfn[v];
    }
    if(dfn[u]==low[u]){
        numtj++;
        while(st[nums]!=u){
            instr[st[nums]]=0;
            bel[st[nums]]=numtj;
            nums--;
        }
        instr[u]=0;
        nums--;
        bel[u]=numtj;
    }
}
void ins2(int from,int to){//加邊
    e1[++cur].to=to;
    e1[cur].pre=head1[from];
    head1[from]=cur;
}
bool ok[maxn];
void dfs(int now,int sum){//深搜
    if(ok[now]){
        ans=max(ans,sum);
    }
    for(int i=head1[now];i;i=e1[i].pre){
        int to=e1[i].to;
        dfs(to,sum+w1[to]);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        ins(x,y);//建圖
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&w[i]);
    }
    int numt;
    scanf("%d%d",&s,&numt);
    for(int i=1;i<=numt;i++){
        scanf("%d",&t[i]);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            tarjan(i);//縮點
        }
    }
    for(int now=1;now<=n;now++){
        w1[bel[now]]+=w[now];
        for(int i=head[now];i;i=e[i].pre){
            int to=e[i].to;
            if(bel[now]!=bel[to]){
                ins2(bel[now],bel[to]);
            }
        }
    }
    for(int i=1;i<=numt;i++){
        ok[bel[t[i]]]=1;
    }
    ans=w1[bel[s]];
    dfs(bel[s],w1[bel[s]]);//爆搜
    printf("%d",ans);
    return 0;
}

大概就是這樣了,坐等被AK。。。
原地爆炸
-------------

轉載於:https://www.cnblogs.com/snzy/p/9690903.html

相關文章