1. 程式人生 > >【海亮集訓&&題解】普及組noip2018賽前練習題解

【海亮集訓&&題解】普及組noip2018賽前練習題解

專輯:海亮集訓&&題解

一、小X與位運算
題目描述
自從上次小X 搞定了完美數之後,他最近在研究一項和計算機密切相關的黑科技。要知道在計算機的內部,資料都是以二進位制的形式來進行儲存的,而它使用的計算方法也和我們平時的加減乘除四則運算 有所不同,它使用的是位運算。那什麼是位運算呢? 基礎位運算有三種符號,分別是 and,or,xor(分別對應 pascal 中的 and,or,xor 三種運算子 號)。
以 and 為例,兩個二進位制數在做 and 運算時,分別對兩個二進位制數的每一位做 and 運算。而對每一 位做and 運算時,遵守以下規則:只有當兩個數的這一位都是 1 時,運算結果才為 1,否則就是 0。例如 1101 和10101 做and 運算之後結果為101(高位不足用0 補齊,最後結果忽略前導0)。 通俗點講 and 運算就是按位做乘法,即將兩個二進位制數從高位到低位依次對齊,然後每一位上對齊 的兩個數相乘即得到這一位的結果 。我們可以列一個簡單的例子來說明個and運算:01101 and 10101 = 00101。
而or,xor 的運算方法類似,唯一不同的是在對每一位做運算時遵循的方法不同。 or 運算遵守以下規則:只有當兩個數的這一位都是 0 時,運算結果才為 0,否則就是 1。例如1101or10101=11101。
xor 運算遵守以下規則:只有當兩個數的這一位相同時,運算結果才為0,否則就是1。例如1101xor10101=11000 。
小 X想知道兩個很大很大的二進位制數,在做完位運算之後, 最後的結果是什麼。而小X 自己無法知道正確答案是什麼,他只好求助於你來幫助他解決這個問題。

輸入格式
輸入資料第一行是一個字串,由字元0 和1組成,表示一個二進位制數。 第二行也是一個字串,由字元0 和1組成,同樣表示一個二進位制數。 第三行還是一個字串,一定是and,or,xor三個中一種,表示運算子號。 注意輸入的二進位制數沒有前導零,字元個數可能會超過255 個。

輸出格式
輸出一行一個字串,由字元0和1 組成,表示最後運算得到的二進位制數。 注意輸出的二進位制數不能帶有前導零,即輸出的第一個字元不能為0。

樣例資料

input
110100
11001
or

output

111101

分析
這道題沒有什麼演算法可言,知識存粹的模擬題,只要細心點按照題目意思模擬下去問題不大。不過需要注意的是前導零的處理以及零的補充

.

那麼具體程式碼如下:

#include<bits/stdc++.h>
using namespace std;
string s3;
string s1,s2;
string s;
void swapp(){
    string t;
    t=s1;s1=s2;s2=t;
}
int main(){
    freopen("bignum.in","r",stdin);
    freopen("bignum.out","w",stdout);
      cin>>s1>>s2;
      cin>>s;
      if (s1.size()<s2.size()) swapp();
      int len=s1.size()-s2.size();
      bool f1=1;
      for (int i=0;i<=len-1;i++){
	      if (s=="and") if (!f1) cout<<'0';else;
	      if (s=="or") if (s1[i]=='1') cout<<'1',f1=0;else if (!f1) cout<<'0';else;
	      if (s=="xor") if (s1[i]=='1') cout<<'1',f1=0;else if (!f1) cout<<'0';else;
	  }
      for (int i=len;i<=s1.size()-1;i++){
	      if (s=="and"){if (s1[i]=='1'&&s2[i-len]=='1') cout<<'1',f1=0;else if (!f1) cout<<'0';else;}
		  else if (s=="or") {if (s1[i]=='1'||s2[i-len]=='1') cout<<'1',f1=0;else if (!f1) cout<<'0';else;}
		  else if (s=="xor"){if (s1[i]!=s2[i-len]) cout<<'1',f1=0;else if (!f1) cout<<'0';else;}
	  }
      fclose(stdin);
      fclose(stdout);
	  return 0;
}

二、小X與機器人
題目描述
小 X 最近對戰勝韓國圍棋大神李世石的 AlphaGo 很感興趣,所以小 X 自己寫了一個叫做 BetaGo 的人工智慧程式(簡稱 AI),這個 BetaGo 會做什麼呢? 小 X 首先想要讓 BetaGo 做到自己在棋盤上落子,這一點 AlphaGo 是由程式設計師來完成的。

小 X 的 設想是這樣的:在棋盤的邊框上放置一個小機器人,這個小機器人會沿著棋盤的邊框移動到最接近落子點的位置,然後伸出它的機械臂將棋子放到棋盤上。這裡面最關鍵的一步是如何讓小機器人在棋盤的邊框上沿著最短的路徑移動,小 X 想請你幫他編個程式解決這個問題。眾所周知,圍棋棋盤大小為 19 × 19(如下圖所示),圖中加粗的一圈即為邊框。我們用一對整數 (x, y) 來表示棋盤上第 x 條橫線(從下往上數)與第 y 條豎線(從左往右數)的交叉點,如上圖中邊框上的 A 點用(6,1)表示,B 點用(10,19)表示,小機器人初始時放置在 (x1, y1) 這個位置上,它想要移動到 (x2, y2) 這個位置上。

(x1, y1)和(x2, y2) 一定是棋盤邊框上的交叉 點 每一步小機器人可以從當前位置移動到相鄰(上下左右)的某個位置上,即每次可以從 (x, y) 移 動到 (x - 1, y)、(x + 1, y)、(x, y - 1)、(x, y + 1) 四個位置中的一個,但是它不能走出或走進棋盤, 也就是說它只能沿著棋盤的邊框移動到相鄰位置,這就意味著任一時刻相鄰位置都恰好只有兩個。 BetaGo 會告訴小機器人最少需要走多少步,但小 X 還是很擔心 BetaGo 有的時候會失控,從而告訴他一個錯誤值。為此小 X 只好求助你,希望你編一個程式計算從 (x1, y1) 沿著棋盤的邊框移動到 (x2, y2) 最少需要走多少步。上圖中從 A 點(6,1)移動到 B 點(10,19)最少需要走 32 步,移動路線是: (6,1)→(5,1)→(4,1)→(3,1)→(2,1)→(1,1)→(1,2)→(1,3)→…… →(1,19)→(2,19)→……→(10,19)。

分析
兩種方法,一種是數學手推,很好理解,這裡不再贅述;另一種就是BFS(雖然顯得很奢侈),這題是可以被當作一題BFS模板題寫的,知識注意的是能走的知識棋盤的一圈,注意vis陣列的賦值
具體程式碼如下:

#include<bits/stdc++.h>
using namespace std;
int st,en,st1,en1;
struct node{
    int x,y;
};
node q[100001];
bool f[101][101];
int ans[101][101];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int main(){
	freopen("betago.in","r",stdin);
	freopen("betago.out","w",stdout);
	int head=1,tail=0;
	scanf("%d %d %d %d",&st,&st1,&en,&en1);
	memset(ans,30,sizeof(ans));
	ans[st][st1]=0;
	q[++tail].x=st;
	q[tail].y=st1;
	memset(f,0,sizeof(f));
	for (int i=1;i<=19;i++) f[i][1]=f[i][19]=f[1][i]=f[19][i]=1;
	for (;head<=tail;head++){
	    node t=q[head];
	    for (int i=0;i<4;i++){
		    int xx=t.x+dx[i],yy=t.y+dy[i];
		    if (!f[xx][yy]) continue;
		    if (ans[xx][yy]>ans[t.x][t.y]+1) ans[xx][yy]=ans[t.x][t.y]+1,q[++tail].x=xx,q[tail].y=yy;
		    if (xx==en&&yy==en1){cout<<ans[en][en1];fclose(stdin);fclose(stdout);return 0;}
		}
	}
	fclose(stdin);
	fclose(stdout);
    return 0;
}

三、賽車
題目描述
小x為了平復自己悲憤的心情,參加了F7賽車決賽的解說工作。作為一位優秀的主持人,他想要了解一下參加決賽的N位選手的情況。經過一番努力,他找到了各位選手前幾站比賽的成績。

決賽就要開始了,比賽規定:第一個到達終點的得到N分,第二個到達終點的得到N-1分,以此類推…最後一個到達終點的得到1分。而且不會有兩位選手同時到達終點。

小x非常忙,所以他想請你幫他統計一下有多少選手有可能成為總冠軍(之前的成績+決賽成績=總成績,總成績最高者為總冠軍,總冠軍可能有多位)。

輸入格式
第一行一個正整數N(3≤N≤300000),代表參加決賽的選手個數。

接下來N行,每行一個正整數Bi,代表第i位選手之前比賽的成績。

輸出格式
一行一個正整數,代表有可能成為總冠軍的選手個數。

樣例資料
input1
3
8
10
9

output1
3

input2
5
15
14
15
12
14

output2
4

#include<bits/stdc++.h>
using namespace std;
int maxx[10000001];
int n;
int a[10000001];
inline bool mycmp(int x,int y){
    return x>y;
}
int main(){
	freopen("racing.in","r",stdin);
	freopen("racing.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1,mycmp);
    maxx[1]=a[1]+1;
    for (int i=2;i<=n;i++)
      maxx[i]=max(maxx[i-1],a[i]+i);
    int ans=1;
    for (int i=2;i<=n;i++) if (a[i]+n>=maxx[i-1]) ans++;
    cout<<ans;
    fclose(stdin);
    fclose(stdout);
    return 0;
}