讓我們來考慮1到n的正整數集合。讓我們把集合中的元素按照字典序排列,例如當n=11時,其順序應該為:1,10,11,2,3,4,5,6,7,8,9。
定義k在n個數中的位置為q(n,k),例如q(11,2)=4。現在給出整數k和m,要求找到最小的n,使得q(n,k)=m。
輸入檔案只有一行,是兩個整數k和m。
輸出檔案只有一行,是最小的n,如果不存在這樣的n就輸出0。
2 4
11
100000001 1000000000
100000000888888879
\(40\%\)的資料,\(1<=k\),\(m<=10^5\);
\(100\%\)的資料,\(1<=k\),\(m<=10^9\)。
參照此篇題解
由於 \(m\) 是 \(k\) 的位次, 所以有 \(m - 1\) 個數排在其之前.
顯然這個題主要討論的就是有多少個數在 \(k\) 之前, 所以首先將 \(m\) 變成 \(m - 1\), 將問題轉化.
既然不能二分, 尋找此題其他性質, 有 \(n - 1\) 個數排在 \(k\) 前面, 且相同位數的數字是連續出現的. 即排序後, 位數不同的數會排成幾個個公差為 \(1\) 的數列, 如 \(q(11, 9) = 11的排列\)
\[\
\]將 \(9\) 前面的數字排序後:
\[\\]
可以看到從 \(1\) 到, \(8\), 從 \(10\) 到 \(11\) 是連續的.
所以可以嘗試按位數來列舉排在 \(k\) 前面的數.
由最開始 \(q(n, k)\) 隨 \(n\) 單調遞增可得, 對於每乙個 \(k\), 一定存在
\[q(k, k) \leq q(n, k)\ ,\ (n \geq k)
\]用 \(min\) 存 \(q(k, k) - 1\), 可以判斷是否有解, 並且作為求解的第一步.
如何求值, 還是根據本題相同位數連續出現的性質, 按位求.
設 \(k\) 有 \(len\) 位.
對於比 \(k\) 位數少的數, 如果其位數為 \(i (i \leq len)\), 則設 \(k\) 的前 \(i\) 位組成的 \(i\) 位數為 \(k_i\), 所有 \(i\) 位數中, 小於等於 \(k_i\) 的數排在 \(k\) 前面, 大於 \(k_i\) 的數排在 \(k\) 後面.
對於和 \(k\) 相同位數的數, 比 \(k\) 小的數都在 \(k\) 前面, 比 \(k\) 大的數都在 \(k\) 後面.
但是對於 \(k\) 本身也計算進去了, 所以需要再減去 \(1\).
得到 \(min\) 的表示式
\[min = (\sum _^ k_i - 10^ + 1) - 1
\]其中 \(k_i = \frac}\)
所以\[min = (\sum _^ \frac} - 10^ + 1) - 1
\]由於\(k\) 前面的最少有 \(min\) 個數, 所以
\(k < min\), 則答案不存在;
\(k = min\), 則答案就是k;
\(k > min\), 則繼續列舉更高位數的數.
這時, 已經求出 \(min\) 且 \(min > m\), 從 \(len + 1\) 位數開始列舉.
其實和位數小於 \(len\) 的數相似, 但是不同的是, \(k_i\) 此時排在 \(k\) 之後, 可以很簡單地寫出上面表示式中 \(i > len\) 的情況.
\(i\) 位數中排在 \(k\) 前面的數的個數
\[k * 10^ - 10^
\]所以只要列舉位數 \(i\), 求出 \(n\) 的位數 \(len_n\)
(由於最高位數的數大概率取不完, 所以這裡先算能取完的位數 \(len_n - 1\), 之後再算缺少的數)
\[\sum _^\left\
k * 10^ - 10^ + 1\ \ (i < len)\\
k * 10^ - 10^\ \ (i \geq len)
\end
\right\}< m
\]這時的 \(n\) 是 \(k * 10^\) 也就是 \(k\) 後面補 '\(0\)', 直到位數達到 \(len_n - 1\).
設上式所求的 \(k\) 前面的數字有 \(q'\) 個, 距離要求的 \(m\) 個還差 \(m - q'\) 個.
還差的這些數無疑位數是 \(len_n\), 而且一定是從 \(10^\) 開始, 到 \(10^ + m - q' - 1\) 結束, 所以最後的答案是
\[n = 10^ + m - q' - 1
\]
#include #include using namespace std;
long long m, k, ten[20], len(0), min(0);
void getlen(long long x)
return;
}void getmin(long long x)
min--; //去掉 k 本身
return;
}int main()
scanf("%lld%lld", &k, &m);
m--;
getlen(k); //求 len
getmin(k); //求 min
if (min > m)
if (min == m)
register int lenn(len + 1); //因為要列舉 lenn, 所以 lenn 充當迴圈控制變數
while (min < m)
min += k * ten[lenn - len] - ten[lenn - 1];
++lenn;
} --lenn; // lenn 從 lenn + 1 變回 lenn
min -=
k * ten[lenn - len] - ten[lenn - 1]; // min 回到 lenn = lenn - 1 時的情況
printf("%lld\n", ten[lenn - 1] + m - min - 1);
// system("pause"); // vsc使用者常常忘記刪除的一行
return 0;
}
洛谷 P2022 有趣的數
讓我們來考慮1到n的正整數集合。讓我們把集合中的元素按照字典序排列,例如當n 11時,其順序應該為 1,10,11,2,3,4,5,6,7,8,9。定義k在n個數中的位置為q n,k 例如q 11,2 4。現在給出整數k和m,要求找到最小的n,使得q n,k m。輸入輸出格式 輸入檔案只有一行,是兩...
洛谷P2022 有趣的數
題目鏈結 首先求出1 k中有多少個在k前面的數的個數,若 m,則無解 比如12345,從第一位開始,1 0 1 共2個 1 0 1 12 10 12共3個 12 10 1 123 100 123 共24個 123 100 1 1234 1000 1234 共235個 1234 1000 1 之後看還...
洛谷 P2022 有趣的數
我們把乙個數稱為有趣的,當且僅當 它的數字只包含0,1,2,3,且這四個數字都出現過至少一次。所有的0都出現在所有的1之前,而所有的2都出現在所有的3之前。最高位數字不為0。因此,符合我們定義的最小的有趣的數是2013。除此以外,4位的有趣的數還有兩個 2031和2301。請計算恰好有n位的有趣的數...