1. 程式人生 > >20171008校內訓練

20171008校內訓練

%d -1 out tab ins lpad 結果 border table

普及難度我居然沒AK。。恥辱。(其實我T3會,把點看成線段了,並且起點和終點沒加特判)

並且我T3 5秒看出正解

L(chess)

【題目描述】

BBS喜歡和LGH下棋,因為這樣能增長他的LG技巧。今天他們又開始下棋。BBS想知道,以當前的局勢,如果雙方都以最優策略下棋,那麽誰能獲得勝利呢?畢竟如果這局會輸,就可以馬上用LFF清理大師清理桌面以保持他的100%的勝率。

棋盤是一個8*8的方格。BBS執白,棋子用’W’表示;LGH執黑,棋子用’B’表示。規則是這樣的:棋盤上為’.’的位置是空格。對於BBS來說,如果他有一個棋子在(r,c)的位置且(r-1,c)的位置為空格,那麽他可以將這個棋子移到(r-1,c)的位置,如果他將任意一個棋子移到了(1,c),那麽他將立即獲得勝利。對於LGH來說,如果他有一個棋子在(r,c)的位置且(r+1,c)的位置為空格,那麽他可以將這個棋子移到(r+1,c)的位置,如果他將任意一個棋子移到了(8,c),那麽他將立即獲得勝利。由於BBS非常的B,所以總是他先手移動一個棋子,然後交換移動權。現在給你整個棋盤,請你輸出這局的結果。

【輸入描述】

輸入一個8*8的棋盤,由’W’,’B’或’.’組成。保證此時第一行沒有W,第八行沒有B。

【輸出描述】

如果這盤BBS能贏,請輸出”BBS”;如果這盤LGH能贏,請輸出”LGH”。

【樣例】

輸入1

輸出1

........

........

.B....B.

....W...

........

..W.....

........

........

BBS

輸入2

輸出2

..B.....

..W.....

......B.

........

.....W..

......B.

........

........

LGH

【說明】

本題中,每10%的數據包括5個點,只有通過全部的5個點才能獲得這10%的分數。

只需計算下兩人的最少獲勝步數然後比較即可。

註意:如果一個W上方有棋子或者一個B下方有棋子。那麽這個W或B不更新最小步數(過不去)

如果棋子是自己的,那麽選那個棋子肯定更優,所以不要管是誰的棋子

技術分享
#include<iostream>
#include<cstdio>
using namespace std;
char c[10][10];
int min1=999999999,min2=999999999;
int main()
{
    //freopen("chess.in","r",stdin);freopen("chess.out","w",stdout);
for(int i=0;i<8;i++)scanf("%s",c[i]); for(int i=0;i<8;i++) for(int j=0;j<8;j++) { bool ok=0; for(int k=0;k<i;k++)if(c[k][j]!=.){ok=1;break;} if(!ok&&c[i][j]==W)min1=min(min1,i); ok=0; for(int k=i+1;k<8;k++)if(c[k][j]!=.){ok=1;break;} if(!ok&&c[i][j]==B)min2=min(min2,7-i); } min1<=min2?puts("BBS"):puts("LGH"); return 0; }
View Code

G(tree)

【題目描述】

BBS有一個n個點的樹,現在告訴你這n-1條邊兩端的點,由於他非常B,所以希望你能幫他把這棵樹放到平面直角坐標系上,並滿足以下條件,要不然BBS的強迫癥會發作:

  1. 不B不行:每個點的坐標必須為整點,即x,y均為整數。同時點的坐標兩兩不同且坐標絕對值小於10^18。
  2. 不B不行:每條樹邊都必須平行於x軸或y軸。
  3. 不S不行:不能有任意兩條樹邊在非樹點處相交。

【輸入描述】

第一行為一個整數n,表示樹點的數量。

接下來的n-1行,每行兩個整數p[i]和q[i],表示點p[i]和點q[i]有連邊。

【輸出描述】

第一行輸出”YES”或”NO”。如果能將這棵樹放到平面直角坐標系上且滿足所以條件,輸出”YES”,否則輸出”NO”。

如果第一行輸出”YES”,那麽接下來的n行,每行輸出兩個整數x[i],y[i],表示點i的坐標為(x[i],y[i])。

如果有多種解,允許輸出任意一種。

【樣例】

輸入

輸出

7

1 2

1 3

2 4

2 5

3 6

3 7

YES

0 0

1 0

0 1

2 0

1 -1

-1 1

0 2

【數據範圍】

對於100%的數據,1<=n<=30

本題中,每10%的數據包括6個點,只有通過全部的6個點才能獲得這10%的分數。

首先,如果一個點與大於4個點有連邊,那麽一定無解,否則有解。

那麽要怎麽構造解呢?

我們把1號點放在(0,0)的位置上(作為樹根),然後選一個很長的長度(10^15之類)的作為這個點與它能走到的點之間的距離,然後往上下左右四個方向拓展

然後遞歸調用,對於一個點,從它出發的距離為它到它父親的距離/2-1(這樣能保證不會交其他樹邊)且它不能從它父親來的方向回去,然後往其他三個方向拓展

然後樹大概就是這樣

技術分享

記錄下每個點的坐標。最後輸出坐標就好了

技術分享
#include<iostream>
#include<cstdio>
using namespace std;
int g[31][5];
long long x[31],y[31];
bool ins(int a,int b)
{
    for(int i=1;i<=4;i++)if(!g[a][i])return 0*(g[a][i]=b);
    return 1;
}
void solve(int k,int fa,int fx,long long len)//1↑4↓2←3→ 
{
    if(fx==1)x[k]=x[fa],y[k]=y[fa]+len;
    if(fx==2)x[k]=x[fa]-len,y[k]=y[fa];
    if(fx==3)x[k]=x[fa]+len,y[k]=y[fa];
    if(fx==4)x[k]=x[fa],y[k]=y[fa]-len;
    int j=0;
    for(int i=1;i<=4;i++)
    {
        if(g[k][i]==fa||!g[k][i])continue;
        j++;if(j+fx==5)j++;solve(g[k][i],k,j,len/2-1);
    }
 } 
int main()
{
    freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);
    int n;scanf("%d",&n);bool ok=0;
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        if(ins(u,v))ok=1;
        if(ins(v,u))ok=1;
    }
    if(ok)return 0*puts("NO");
    x[1]=0;y[1]=0;
    for(int i=1;i<=4;i++)
    {
        if(!g[1][i])break;
        solve(g[1][i],1,i,100000000000000ll);
    }
    puts("YES");
    for(int i=1;i<=n;i++)cout<<x[i]<<" "<<y[i]<<endl;
    return 0;
 } 
View Code

B(journey)

【題目描述】

BBS作為一名老司機,最喜歡的自然不過開車。今天他新進口了一輛“渦輪噴壓”車,可以在助跑至少s個單位後在空中飛至多d個單位。本來開車是一件很開心的事,從石頭上飛過去也是件很開心的事,可是兩件事在一起……怎麽會這樣呢?瀚嵩現在在0的位置,他要開到m的位置,在這段路上有n塊石頭,現在他知道這n塊石頭的位置,他想請教你要如何開車才能經過這一段路?

【輸入描述】

第一行有四個數,分別是n,m,s,d

第二行為n個數,是n個石頭的位置w[1],w[2]…w[n]

【輸出描述】

輸出有若幹行,為你開車的過程,每個過程一行,方法有兩種:

1、“RUN X”這個表示在地上開X個單位長度,不能有兩個連續的RUN命令

2、“JUMP X”這個表示在空中飛X個單位長度,這個命令的前一個操作要求要助跑距離超過s,飛的長度不超過d

如果有多種過程能到達終點,允許輸出任意一種。

如果不能到達終點,輸出“Impossible”

【樣例】

輸入

輸出

3 10 1 3

3 4 7

RUN 2
JUMP 3
RUN 1
JUMP 2
RUN 2

【樣例解釋】

【數據範圍】

對於40%的數據,n<=10並捆綁測試

對於70%的數據,n<=100000

對於100%的數據,

1<=n<=200000,2<=m<=10^9,1<=s,d<=10^9,1<=w[i]<=m-1,w[i]<w[i+1]

技術分享

X為1到10^9內的整數

貪心。

如果兩個相鄰石頭之間的距離夠助跑,那麽再前一個石頭位置+1降落,在後一個石頭位置-1起飛即可。這樣能使接下來能飛行時間最大化

如果不夠助跑,那只能飛咯。如果當前石頭位置+1-起飛的位置距離大於能飛行的距離,輸出Impossible。

註意點在文章開頭。

對於起點的特判,如果0~第一塊石頭位置-1都不夠助跑的話,輸出Impossible。

對於終點的特判,如果飛行距離不夠到最後一塊石頭的位置+1,輸出Impossible,否則在最後一塊石頭的位置+1處降落,開到終點就好了

技術分享
#include<iostream>
#include<cstdio>
using namespace std;
int ok[1000100];//正run,負jump 
int a[200100];
int main()
{ 
freopen("journey.in","r",stdin);freopen("journey.out","w",stdout);
    int n,m,s,d;scanf("%d%d%d%d",&n,&m,&s,&d);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);a[0]=-1;
    int tot=0,last;//起飛的位置 
    if(a[1]-1>=s){last=a[1]-1;ok[++tot]=a[1]-1;}
    else return 0*puts("Impossible");
    for(int i=2;i<=n;i++)
    {
        if(a[i]-a[i-1]-2>=s)
        {
            ok[++tot]=-(a[i-1]-last+1);
            last=a[i]-1;
            ok[++tot]=a[i]-a[i-1]-2;
        }
        else if(a[i]-last+1>d)return 0*puts("Impossible");
    }
    if(a[n]-last+1>d)return 0*puts("Impossible");
    else 
    {
        ok[++tot]=-(a[n]-last+1);
        if(m-(a[n]+1)!=0)ok[++tot]=m-(a[n]+1);
    }
    for(int i=1;i<=tot;i++)
    {
        if(ok[i]>0)printf("RUN %d\n",ok[i]);
        else printf("JUMP %d\n",-ok[i]);
    }
    return 0;
 } 
View Code

不得不說,這3題代碼量是真的小

20171008校內訓練