【Coel.解題報告】【場外人士的拙劣表演】P7960 [NOIP2021]報數
題前碎語
很遺憾,今年沒能參加\(NOIp\),甚至\(CSP\)都沒去。
因為初三一整年都在頹廢,覺得自己太菜了只能當分母
所以就作為一個場外人士來做題了!
題目梗概:[NOIP2021]報數
洛谷傳送門
報數遊戲是一個廣為流傳的休閒小遊戲。參加遊戲的每個人要按一定順序輪流報數,但如果下一個報的數是 \(7\) 的倍數,或十進位制表示中含有數字 \(7\),就必須跳過這個數,否則就輸掉了遊戲。
在一個風和日麗的下午,剛剛結束 SPC20nn 比賽的小 r 和小 z 閒得無聊玩起了這個報數遊戲。但在只有兩個人玩的情況下計算起來還是比較容易的,因此他們玩了很久也沒分出勝負。此時小 z 靈光一閃,決定把這個遊戲加強:任何一個十進位制中含有數字 \(7\)
形式化地,設 \(p(x)\) 表示 \(x\) 的十進位制表示中是否含有數字 \(x\),若含有則 \(p(x) = 1\),否則 \(p(x) = 0\)。則一個正整數 \(x\) 不能被報出,當且僅當存在正整數 \(y\) 和 \(z\) ,使得 \(x = yz\) 且 \(p(y) = 1\)。
例如,如果小 r 報出了 \(6\) ,由於\(7\) 不能報,所以小 z 下一個需要報 \(8\);如果小 r 報出了 \(33\),則由於 \(34 = 17 \times 2\),\(35 = 7 \times 5\) 都不能報,小 z 下一個需要報出 \(36\)
現在小 r 的上一個數報出了 \(x\),小 z 想快速算出他下一個數要報多少,不過他很快就發現這個遊戲可比原版的遊戲難算多了,於是他需要你的幫助。當然,如果小 r 報出的 x 本身是不能報出的,你也要快速反應過來小 r 輸了才行。
由於小 r 和小 z 玩了很長時間遊戲,你也需要回答小 z 的很多個問題。
輸入格式
從number.in中讀入資料。
第一行,一個正整數 \(T\) 表示小 z 詢問的數量。
接下來 \(T\) 行,每行一個正整數 \(x\)
輸出格式
輸出至number.out中。
輸出共 \(T\) 行,每行一個整數,如果小 r 這一次報出的數是不能報出的,輸出 \(-1\),否則輸出小 z 下一次報出的數是多少。
【資料範圍】
對於 \(10\%\) 的資料,\(T \leq 10\),\(x \leq 100\)。
對於 \(30\%\) 的資料,\(T \leq 100\),\(x \leq 1000\)。
對於 \(50\%\) 的資料,\(T \leq 1000\),\(x \leq 10000\)。
對於 \(70\%\) 的資料,\(T \leq 10000\),\(x \leq 2 \times {10}^5\)。
對於 \(100\%\) 的資料,\(1 \le T \leq 2 \times {10}^5\),\(1 \le x \leq {10}^7\)。
\(NOIp\)的第一道題,難度十分友好(個人感覺黃題上位)
第一眼看這題就想到用打表,不過仔細思考了一下發現\(10^7\)不算太大,可以直接在程式裡打。其實也是因為我懶得再寫一個打表程式
篩完直接二分查詢就行了,時間複雜度為\(O(maxn +Tlogn)\)(如果在程式外打表就是\(O(Tlogn)\)),可以通過本題。
程式碼如下:
#include<cstdio>
#include<algorithm>
#include<vector>
#define maxn 10001000
using namespace std;
int T,n;
bool vis[maxn];
vector<int>excel;
inline bool check(int i)//篩出帶7 的數
{
while(i)
{
if(i%10==7)return true;
i/=10;
}
return false;
}
inline void Hit_The_Excel()//愉快的打表環節
{
for(register int i=1;i<=maxn;i++)
{
vis[i]=check(i)?true:vis[i];
if(vis[i])
{
if(i*2<=maxn)vis[i*2]=true;
for(register int j=1;i*(j*2+1)<=maxn;j++)
vis[i*(j*2+1)]=true;
continue;
} else excel.push_back(i);
}
}
int main()
{
#ifndef ONLINE_JUDGE//養成檔案IO的好習慣
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
#endif
Hit_The_Excel();
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
vector<int>::iterator it=lower_bound(excel.begin(),excel.end(),n);//用迭代器表示位置
if(it==excel.end()||(*it)!=n)//對方輸了,輸出-1
puts("-1");
else ++it,printf("%d\n",*it);//輸出下一個數
}
return 0;
}
題後閒話
看了一下這次\(NOIp\)的情況,廣西的1=線預測為125,也就是說做出這道題就大概率能拿2=了,哈哈!
所以我為什麼要放棄這次參加機會呢?如果參加,或許還可以撈個獎,可惜沒有可能了……
明年再戰吧!