2018百度之星程序设计大赛初赛B——1002hex
HDU-6381
題目:
度度熊最喜歡六邊形的網(wǎng)格了!!!
上圖由左至右依序是邊長(zhǎng)為?11,?22?以及?33?的六邊形網(wǎng)格。
另外,每個(gè)六邊形網(wǎng)格最左側(cè)的格子稱之為這個(gè)六邊形網(wǎng)格的錨點(diǎn),上圖中每個(gè)六邊形網(wǎng)格的錨點(diǎn)都以藍(lán)色著色。
定義在六邊形網(wǎng)格上的坐標(biāo)系統(tǒng):相對(duì)一個(gè)坐標(biāo)為?(x,y)(x,y)?的中心格子,其周圍格子的坐標(biāo)定義為下圖中所示的值:
給定一個(gè)大小為?LL?的六邊形主網(wǎng)格,這個(gè)六邊形主網(wǎng)格的錨點(diǎn)的坐標(biāo)為?(1,L)(1,L)。這個(gè)主網(wǎng)格中每一個(gè)格子上都有一個(gè)顏色,以?00?至?6161?之間的整數(shù)代表。對(duì)于這個(gè)主網(wǎng)格有?QQ?個(gè)詢問,每個(gè)詢問將會(huì)詢問這個(gè)主網(wǎng)格中某一個(gè)六邊形子網(wǎng)格的范圍中,包含有幾個(gè)不一樣的顏色。
一個(gè)詢問以三個(gè)整數(shù)?<x,y,l><x,y,l>?來表示其中一個(gè)六邊形的子網(wǎng)格,依序?yàn)槠溴^點(diǎn)的坐標(biāo)?(x,y)(x,y)?以及其大小?ll。例如,下圖為一個(gè)大小?L=3L=3?的主網(wǎng)格,格子內(nèi)部的數(shù)字為其坐標(biāo),而非格子的顏色。綠色邊框所包圍的子網(wǎng)格是一個(gè)錨點(diǎn)坐標(biāo)為?(5,3)(5,3),大小?l=2l=2?的子網(wǎng)格,以?<5,3,2><5,3,2>?表示,同時(shí),紅色邊框表示?<3,1,1><3,1,1>?的子網(wǎng)格。
Input
輸入的第一行有一個(gè)正整數(shù)?TT,代表接下來有幾筆測(cè)試資料。
對(duì)于每筆測(cè)試資料: 第一行有一個(gè)正整數(shù)?LL。 接下來的?2L?12L?1?行輸入代表一個(gè)大小為?LL?的六邊形網(wǎng)格。 六邊形網(wǎng)格將會(huì)透過下列的過程轉(zhuǎn)換至輸入的格式:
接下來的一行有一個(gè)整數(shù)?QQ?代表接下來有幾組詢問。 接下來的?QQ?行每行有三個(gè)正整數(shù)?xx,?yy?及?ll,代表一組詢問?<x,y,l><x,y,l>。
下圖為范例測(cè)試資料中的六邊形網(wǎng)格,格子內(nèi)顯示的數(shù)字代表顏色,而非坐標(biāo):
- 1≤L≤2501≤L≤250
- 代表六邊形網(wǎng)格的字符串中只會(huì)有 0-9a-zA-Z 這些字符。
- 0≤Q≤3×1050≤Q≤3×10?5??
- 1≤x≤4L?31≤x≤4L?3
- 1≤y≤2L?11≤y≤2L?1
- 1≤l≤L1≤l≤L
- (x,y)(x,y)?一定是給定的六邊形網(wǎng)格中合法的格子點(diǎn)。
- <x,y,l><x,y,l>?詢問的子六邊形網(wǎng)格一定完整的位于主網(wǎng)格中。
- 1≤T≤151≤T≤15
- 至多?11?筆測(cè)試資料中的?L>50L>50
- 至多?11?筆測(cè)試資料中的?Q>1000Q>1000
Output
對(duì)于每一筆測(cè)試資料,對(duì)于每一個(gè)詢問,請(qǐng)依序各自在一行內(nèi)輸出一個(gè)整數(shù),代表此詢問的答案。 兩筆測(cè)試資料間請(qǐng)不要輸出多余的空白行。
Sample Input
1 3 012 3456 789ab cdef ghi 10 1 3 1 1 3 2 1 3 3 9 3 1 7 3 1 3 3 1 3 3 2 5 3 1 5 3 2 2 2 2Sample Output
1 7 19 1 1 1 7 1 7 7(題目復(fù)制過來后部分文本重復(fù)了)
題目看起來很長(zhǎng),加上有那么多六邊形好像很麻煩,但其實(shí)根本問題還是:
給一組東西,多次詢問某個(gè)范圍,求這個(gè)范圍內(nèi)的某個(gè)/某種值。
符合rmq的條件,所以可以嘗試用rmq解決。
這道題其實(shí)可以算是資格賽1002的進(jìn)階版,同樣使用rmq算法,只不過那道題給的是一個(gè)數(shù)組,求的是最值,這里給的是一組六邊形,求的是顏色的種數(shù)。
rmq算法用到了動(dòng)態(tài)規(guī)劃,那么就要有狀態(tài)。
題目的63個(gè)顏色可以用63個(gè)二進(jìn)制表示,出現(xiàn)哪種顏色,哪一位用“1”表示,有點(diǎn)類似資格賽1001的思路。可以用long long 類型的數(shù)來表示每組六邊形的狀態(tài)。
long long dp [2*MAXL-1] [4*MAXL-3] [9]
dp [i] [j] [k] 表示以點(diǎn)(i,j)為錨點(diǎn),邊長(zhǎng)為 2的k次方 的六邊形的狀態(tài)(所包含的顏色)。
狀態(tài)轉(zhuǎn)移:
rmq算法是以2倍增的思想來不斷進(jìn)行處理的,對(duì)應(yīng)這道題也就是:對(duì)于邊長(zhǎng)為2的k次方的六邊形,用邊長(zhǎng)為2的(k-1)次方的六邊形來覆蓋處理它。
以邊長(zhǎng)為2的六邊形來看,我們可以用6個(gè)點(diǎn)對(duì)應(yīng)的6個(gè)邊長(zhǎng)為1的六邊形 + 中心六邊形來覆蓋它;
當(dāng)邊長(zhǎng)=2^k?>2時(shí),同樣的,6個(gè)點(diǎn)對(duì)應(yīng)的6個(gè)2^(k-1) 個(gè)六邊形 + 中心六邊形可以表示它。(這里的六邊形會(huì)有重疊的部分,但不會(huì)有遺漏的部分)
為了方便放進(jìn)數(shù)組,先將題目中給出的坐標(biāo)表示換一下位置,比如題目中(1,3)的點(diǎn)我們表示成(3,1)放進(jìn)六邊形數(shù)組six[3][1]。
所以接下來就是確定這7個(gè)六邊形的錨點(diǎn)的問題了。
可以自己動(dòng)手再畫一個(gè)邊長(zhǎng)為4的六邊形,對(duì)比邊長(zhǎng)為2,邊長(zhǎng)為1的六邊形,多利用2^k,2^(k-1),2^(k+1)不難得出七個(gè)六邊形的錨點(diǎn)坐標(biāo):
/**七個(gè)六邊形位置:1 ? ? ? ?23 ? 7 ? ? ??45 ? ? ? ?6*/ int i1 = i-(1<<(k-1));int j1 = j + (1<<(k-1));int i2 = i - (1<<(k-1));int j2 = j + (1<<(k-1)) + (1<<k);int i3 = i;int j3 = j;int i4 = i;int j4 = j + (1<<(k+1));int i5 = i + (1<<(k-1));int j5 = j + (1<<(k-1));int i6 = i + (1<<(k-1));int j6 = j + (1<<(k-1)) + (1<<k);int i7 = i;int j7 = j + (1<<(k+1)) - 2;所以,
狀態(tài)轉(zhuǎn)移方程:
dp[i][j][k] = dp[i1][j1][k-1] | dp[i2][j2][k-1]??| dp[i3][j3][k-1] | dp[i4][j4][k-1]? | dp[i5][j5][k-1] | dp[i6][j6][k-1]? | dp[i7][j7][k-1];
也就是這7個(gè)六邊形做 按位或( | )操作 —— 有1為1,全0為0,這個(gè)運(yùn)算就可以來表示這七個(gè)六邊形組合在一起的顏色情況了。
初始狀態(tài):
k=0,只有一個(gè)六邊形,它的狀態(tài)就是它本身的顏色。
dp[i][j][0] = (long long)1<<six[i][j]
dp數(shù)組存儲(chǔ)完之后,剩下的就是查詢了。
由于rmq用的是2的倍增,在這道題中也就是計(jì)算了1,2,4,8 ... 邊長(zhǎng)的顏色情況,那么對(duì)于3,5,6,7這些邊長(zhǎng)沒辦法直接在dp數(shù)組里面找到,所以查詢?nèi)匀皇欠侄尾樵儭M瑯拥牡览肀热缳Y格賽1002。
先打表,求一下0-250這些數(shù)的log2是多少,存儲(chǔ)在Log2數(shù)組中。(這里存儲(chǔ)的時(shí)候是向下取整,也就是說log2(3) = 1)
然后,在查詢時(shí),我們只需要6個(gè)頂點(diǎn)對(duì)應(yīng)的六邊形就可以覆蓋待查詢的六邊形了,因?yàn)橹行牧呅慰隙òㄔ谶@個(gè)6個(gè)中。
設(shè)查詢的邊長(zhǎng)為L(zhǎng),Log2[L] = k;
查詢區(qū)間的確定,實(shí)際上是與 (L - 2^k)有關(guān),可以得到六個(gè)六邊形的錨點(diǎn)坐標(biāo),并進(jìn)而得到這六個(gè)六邊形組成的顏色情況n:
long long n;int temp = l - (1<<k); // L - 2^kint i1 = x - temp;int j1 = y + temp;int i2 = x - temp;int j2 = y + 3 * temp;int i3 = x;int j3 = y;int i4 = x;int j4 = y + 4 * temp;int i5 = x + temp;int j5 = y + temp;int i6 = x + temp;int j6 = y + 3 * temp;n = (long long)dp[i1][j1][k] | dp[i2][j2][k]| dp[i3][j3][k] | dp[i4][j4][k]| dp[i5][j5][k] | dp[i6][j6][k];最后,只要數(shù)一下 n 里面有多少個(gè)1,那么就有多少種顏色,就是答案了。
代碼:
// // main.cpp // 初賽B1002 // // Created by jinyu on 2018/8/13. // Copyright ? 2018年 jinyu. All rights reserved. //#include <iostream> #include <cstdio> #include <algorithm> using namespace std;/**L , L 個(gè) : 1L-1, L+1 : 2L-2, L+2 : 3... : ...1 , 2L-1 : ...2 , 2L-2 :3 , 2L-3 :... :L , L : 2L-1*/const int MAXL = 250+7;int six[2*MAXL-1][4*MAXL-3]; int L; long long dp[2*MAXL-1][4*MAXL-3][9]; int Log2[MAXL];void rmq(){for(int k = 1;(1<<k)<=L;k++){for(int i = 1;i+(1<<(k-1))<=2*L-1;i++){for(int j = 1;j+(1<<(k-1))+(1<<k)<=4*L-3;j++){if(six[i][j]==-1)continue;if((i-(1<<(k-1)))<1)continue;int i1 = i-(1<<(k-1));int j1 = j + (1<<(k-1));int i2 = i - (1<<(k-1));int j2 = j + (1<<(k-1)) + (1<<k);int i3 = i;int j3 = j;int i4 = i;int j4 = j + (1<<(k+1));int i5 = i + (1<<(k-1));int j5 = j + (1<<(k-1));int i6 = i + (1<<(k-1));int j6 = j + (1<<(k-1)) + (1<<k);int i7 = i;int j7 = j + (1<<(k+1)) - 2;dp[i][j][k] = dp[i1][j1][k-1] | dp[i2][j2][k-1]| dp[i3][j3][k-1] | dp[i4][j4][k-1]| dp[i5][j5][k-1] | dp[i6][j6][k-1]| dp[i7][j7][k-1];}}} }int query(int x,int y,int l){int k = Log2[l];int temp = l - (1<<k);if(k==0)return 1;long long n;int i1 = x - temp;int j1 = y + temp;int i2 = x - temp;int j2 = y + 3 * temp;int i3 = x;int j3 = y;int i4 = x;int j4 = y + 4 * temp;int i5 = x + temp;int j5 = y + temp;int i6 = x + temp;int j6 = y + 3 * temp;n = (long long)dp[i1][j1][k] | dp[i2][j2][k]| dp[i3][j3][k] | dp[i4][j4][k]| dp[i5][j5][k] | dp[i6][j6][k];int ans = 0;//判斷n中1的個(gè)數(shù)while(n){n = n & (n-1);ans++;}return ans; }int main(){for(int i = 0;i<MAXL;i++){Log2[i] = i==0?-1:Log2[i>>1]+1;}int T;scanf("%d",&T);while(T--){scanf("%d",&L);for(int i = 0;i<4*L+7;i++){for(int j = 0;j<4*L+7;j++)six[i][j] = -1;}getchar();char c;int k = 1;for(int i = L;i>=1;--i){int tempi = i;int num = L+(L-i);while(num--){c = getchar();if(c>='0' && c<='9'){six[k][tempi] = c-'0';}else if(c>='a' && c<='z'){six[k][tempi] = c-'a'+10;}else if(c>='A' && c<='Z'){six[k][tempi] = c-'A'+36;}tempi+=2;}getchar();k++;}for(int i = 2;i<=L;++i){int tempi = i;int num = L+(L-i);while(num--){c = getchar();if(c>='0' && c<='9'){six[k][tempi] = c-'0';}else if(c>='a' && c<='z'){six[k][tempi] = c-'a'+10;}else if(c>='A' && c<='Z'){six[k][tempi] = c-'A'+36;}tempi+=2;}getchar();k++;}// for(int i = 1;i<=2*L-1;i++){ // for(int j = 1;j<=4*L-3;j++) // { // if(six[i][j]==-1) // cout<<" "; // else // cout<<six[i][j]<<" "; // } // cout<<endl; // }for(int i = 1;i<=2*L-1;i++){for(int j = 1;j<=4*L-3;j++){if(six[i][j]==-1)dp[i][j][0] = (long long)0;elsedp[i][j][0] = (long long)1<<six[i][j];}}rmq();int Q;scanf("%d",&Q);while(Q--){int x,y,l;scanf("%d%d%d",&y,&x,&l);printf("%d\n",query(x,y,l));}// printf("3 1 1 : %lld\n",dp[3][1][1]);}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的2018百度之星程序设计大赛初赛B——1002hex的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “约见”面试官系列之常见面试题之第七十三
- 下一篇: “约见”面试官系列之常见面试题之第五十篇