yjc把核彈發射密碼忘掉了……其實是密碼被加密了,但是yjc不會解密。密碼由n個數字組成,第i個數字被加密成了如下形式:第k小的滿足(2^l)|(p-1)且p為質數的p。yjc希望你能幫他算出密碼是多少。
輸入格式:
第一行包含乙個整數n,表示密碼中的數字個數。
接下來n行每行兩個整數l和k,表示乙個數字的加密形式。
注意,輸入格式變更,請注意l和k的先後順序
輸出格式:
輸出n行,第i行乙個整數,表示第i個數字。
輸入樣例#1:
221 92
23 9
輸出樣例#1:
1998585857998244353
對於50%的資料,滿足18≤n,l≤1000。
對於100%的資料,滿足12≤n,l≤500000,保證答案<2^31。
分析:比較考驗人品的一道題。
暴力找的話有30分.時間都浪費在了怎麼判斷素數上,而且詢問很多,每個數可能會被判斷多次,考慮怎麼優化它們.
對於素數的判斷,可以用乙個比較考驗人品的演算法miller rabin測試,每一次都有大約1/4的概率會出錯,因此要多判幾次,但是多判幾次又會超時,將次數控制在3次到5次就可以了.這裡利用費馬小定理+快速冪進行判斷.
接下來考慮怎麼不重複判斷同乙個數。我們將詢問的l按照降序排序,符合條件的數肯定是k*2^i+1的形式,我們先從大到小列舉i,再列舉k,k列舉的是奇數,因為如果我們乙個乙個地列舉,如果k=2,那麼就會跳到2^(i+1) + 1上去,而我們之前已經計算過了這個數,會造成重複.將所得的素數排個序.
最後考慮怎麼快速得到第k小的p,因為我們已經將所得的素數排好序了,所以我們可以二分查詢,由於之前我們將詢問的l按照降序排列,那麼得到的滿足要求的數就構成了乙個又乙個的區間,那麼利用樹狀陣列來維護有多少個比它小的就可以了.
聽說還有還可以用等差數列篩法,orz
#include #include#include
#include
using
namespace
std;
const
int maxn = 1
<< 20,maxm = 600010
;long
long
n,cnt,num[maxm],prime[maxm],t[maxm],ans[maxm],c[maxm];
struct
node
e[maxm];
long
long qpow(long
long a, long
long b, long
long
mod)
return
ans;
}bool isok(long
long
x)bool
cmp1(node a, node b)
intmain()
sort(e + 1, e + 1 +n, cmp1);
for (int i = 30; i >= 12; num[i--] =cnt)
for (int j = 1; 1ll * j * (1
<< i) < (1ll << 31) - 1; j += 2
)
if (isok(j * (1
<< i) + 1
)) prime[++cnt] = j * (1
<< i) + 1
; memcpy(t, prime,
sizeof
(prime));
sort(t + 1, t + 1 +cnt);
for (int i = 1; i <= cnt; i++)
prime[i] = lower_bound(t + 1, t + 1 + cnt, prime[i]) -t; //實際上是把符合要求的質數和離散化了
int cur = 1
;
for (int i = 1; i <= n; i++)
int l = 0, r = maxn, sum = 0
;;
while (lelse l = mid + 1
; }
ans[e[i].id] =t[l];
}for (int i = 1; i <= n; i++)
printf(
"%lld\n
", ans[i]);
return0;
}
noip模擬賽 密碼
表示沒看懂演算法3 問題描述 有壓迫,就有反抗。mored的寵物在法庭的幫助下終於反抗了。作為乙隻聰明的寵物,他打算把魔法使mored的魔法書盜去,奪取mored的魔法能力。但mored怎麼會讓自己的魔法書輕易地被盜取?mored在魔法書上設定了乙個密碼鎖,密碼鎖上有乙個問題。施以斯臥鋪魔法吧,你有...
NOIP模擬賽 老師
題目描述 一座有n層的教學樓裡有一些學生,第i 0 i n 層有studentsi個學生。你被給定了乙個數k,如果第i層有x個學生,那麼這一層需要 x k 個老師。你可以調整每個學生的樓層,但是每個學生至多只能調整一層,就是說第i層的學生只能去第i 1層 如果有的話 第i層 第i 1層 如果i 1 ...
NOIP模擬賽 分錢
題目描述 兩個人在街上撿到了一些錢,這些錢共有n張,他們等了很久也沒有等來失主,於是決定把錢平分。但錢可能無法平分。他們先把能夠平分的錢盡量先平分了,使得剩下不能平分的錢盡量少。這些不能平分的錢怎麼辦呢他?他們決定拿去賭場裡面賭一把。他們運氣太好了,那些不能平分的錢變成了雙倍,於是他們就把那個錢分了...