創作內容

4 GP

數數字

作者:小坤│2018-05-22 01:23:57│巴幣:8│人氣:537

/*
數數字

假設今天有一種特殊的方陣,邊長為 7,且該方陣的每個元素是由外到內從 1 開始不斷增加,如以下範例:
①①①①①①①
①②②②②②①
①②③③③②①
①②③④③②①
①②③③③②①
①②②②②②①
①①①①①①①
給定一個數字 k(例如 11),則從方陣的左上角開始,以斜向且接續的方式數到第 11 個數字(數的方式如下圖),例如以上的範例為 1,則問題的答案即為 1。
①②⑥⑦⑮
③⑤⑧⑭⑯
④⑨⑬⑰㉒
⑩⑫⑱㉑㉓
⑪⑲⑳㉔㉕
Input
第一行代表測資的筆數 n。接下來有 n 行,每行兩個數字以空白間隔,第一個數字代表方陣的邊長,第二個數字 k 代表要求的第 k 個數。
Output
將數到的第 k 個數字輸出。
範例輸入:
3
7 11
3 5
4 9
範例輸出:
1
2
2
*/

/*
[解題概念]
設現有邊長 j 的正方形,欲求第 k 個的數字。

將每一斜排視為一組,這將成為鏡射成對的數字,
即第 k 數字會和第 j * j - k + 1 的數字相同。

##加速重點部分 #p.s. plusToN (t) = (1 + t) * t / 2
接著找尋第 k 個數字位於第幾斜排(n+1)。

以題目的第 11 個數字為例子,11 必定介於 10 和 15 之間,
即 plusToN(4) < 11 <= plusToN(5),
也就是第 k 個數字必定位於到上一排的數字總數與到這一排的數字總數之間。
即 plusToN(n) < k <= plusToN(n + 1)。

由於公式 plusToN(t) = (1 + t) * t / 2 = (t + t^2) / 2 趨近於 (t^2)/2,
即 plusToN(t) ~= (t^2)/2。
以上面的例子來說,為了找到第 11 個數字最近的排數 4,
將 11 帶入公式 11 = (t^2)/2 求出 t 值,並向下取整數。
(11 不是一個排的最後,所以 t 值不會是整數)

因此,可以找到一個趨近值 m = floor(sqrt(k*2)),表示為 m = floor(sqrt(k*2)) ~= n,
用這個 m 值開始尋找,除了 n 極小的狀況,會產生 m > n 的現象以外,
其他都會是 n >= m 的狀況,大部分都是 n == m,
此時從 m - 1 開始找,就可以有效率地找到 n 值。

接著,取得第 k 個數字是該斜排的第幾個數字,這可以輕易地藉由 k - plusToN(n) 做到。

由於該斜排的數字,長得像是 "1 ... n/2 ... 1" ,本身也是鏡射。
若第 k 個數字的索引值(該斜排的第幾個數字),
超過該排最大可能的數字(以題目的 7 11 來舉例就是 4),那麼就將 k 做鏡射,
修正完的就是最終答案。

if (index > maxNum) index = i + 1 - index + 1;
這一行:
這邊 i + 1 是 n + 1,拿 7 11 來說就是 5
代表 11 12 13 14 15 那一行
如果最後 index 是 5
也就是 15 - 10
那修正的方式,就是 5 - 5 + 1
也就是 (4+1) - index + 1
因為那一行是
11 12 13 14 15
值分別是
1 2 3 2 1
*/

#include <iostream>
#include <cmath>
using namespace std;

int plusToN(int n) {
return (1 + n) * n / 2;
}

int getAns(int j, int k) {
    int halfup = plusToN(j);
    if (k > halfup) k = j * j - k + 1;
    //
    int m = (int) floor(sqrt(k*2));
    for (int i = m - 1;;++i) {
        int low = plusToN(i), high = plusToN(i + 1);
        if (low < k && k <= high) {
            int index = k - low;
int maxNum = (i + 1) / 2;
if (index > maxNum) index = i + 1 - index + 1;
            return index;
        }
    }
}

int main() {
    int times, j, k;
    cin >> times;
    while(times--) {
        cin >> j >> k;
        cout << getAns(j, k) << endl;
    }
}



今天不清楚為什麼發神經
看到這篇突然想到更好的解法

程式碼的部分,為了好讀我沒有做太多的加速
整篇的精華應該在解題策略上
這個演算法挺不錯的
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=3997380
All rights reserved. 版權所有,保留一切權利

相關創作

留言共 9 篇留言

極巨龍神塔奇
我用我的code就跟同學解釋很久了 他們一定不會懂你的XD

05-22 02:27

小坤
我中間有這段code的解釋,應該還行啦05-22 08:11
小坤
你就跟他們說 "拜託我念的大學學生寫的 code,你大學的哪有看不懂的道理"05-22 08:16
小坤
不如說,我看你的 code 只覺得是很暴力的數 XD05-22 11:12
水狼陽介
恩...種田心得XD?

05-22 10:21

小坤
假設有一塊地是 13 x 13 的正方形田地,
最外圈種價值 1 的作物,以此類推種到正中間價值 7 的作物,
請問,按照文中的方式數第 37 顆作物是價值多少的作物?05-22 11:06
水狼陽介
感覺是minecraft用來計算火把亮度的演算法(欸

05-22 11:12

小坤
www 其實 minecraft 算火把亮度還沒這麼複雜啦05-22 11:25
小坤
被人說找趨近值的地方略過太多太難懂QQ
嚇得我趕緊回去補描述05-22 11:47
水狼陽介
真的很難懂阿,我完全看不懂呦(欸你根本沒有要看的意思吧

05-22 12:12

小坤
嗚嗚嗚,我中文越來越爛是否QQ05-22 12:15
水狼陽介
主要是因為牽涉到座標,可能要附圖,純文字大概比較難理解你的意思,我等等抽空看一下是否能看懂

05-22 12:16

CRTS
i + 1 - (index -1),你mirror 這樣寫就好懂多了
從後面數過來,offset同樣格數

05-22 12:36

小坤
www05-22 12:44
極巨龍神塔奇
我是暴力數啊 因為題目是我改的 原本的題目讓同學都不知道怎麼數

05-22 12:42

極巨龍神塔奇
我需要把整個數的過程演示一遍

05-22 12:43

小坤
我有大概猜到你把過程中所有數都05-22 13:49
小坤
找出來05-22 13:49
嗡嗡
再次見到數數字w
聽說最近流行在小屋塞程式碼XD

05-22 18:27

小坤
沒有這回事ww 我只是看到就突然想寫05-22 23:55
我要留言提醒:您尚未登入,請先登入再留言

4喜歡★kyob1010 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:Don't S... 後一篇:Don’t Starve...

追蹤私訊切換新版閱覽

作品資料夾

ilove487  
【讀墨】2023年台灣大眾小說人氣票選ーー《致一百光年外的你》名列候補!!看更多我要大聲說4小時前


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】