1. 程式人生 > >ssl1274.A 模擬+數學方法

ssl1274.A 模擬+數學方法

題目

有一個正整數 a, 有 q 次詢問, 每次給定一個正整數 bi , 求 a^bi 的值. 由於答案可能很大, 你只需要輸出答案對 p 取模的結果。 又由於詢問可能很多, 給定一個引數 k, 你只需要輸出對於所有 k 的整數倍 i(0 < i ≤ q), 第一 次詢問到第 i 次詢問的結果的異或和. 為了防止輸入檔案過大, 每次詢問的值以以下方法生成: 設 bi 為第 i 次詢問的值, 給定 b0, l, m, c,i > 0 時,bi 滿足 bi = (m ∗ bi−1 + c)mod l

資料規模如下
在這裡插入圖片描述

題解

直接模擬即可
對於bib_i可以直接一個一個求,ONO(N)

時間可以接受
然後問題轉化為如何快速求aba^b
可以預處理出aa的1~1000000次方,用abiab_i存;然後在預處理出aa1000000110000002...100000010000001000000^{1},1000000^{2}...1000000^{1000000}次,用baiba_i存。
對於aba^b,把b拆成兩半(如a12345678a^{12345678}拆成ab[45678]ba[123]ab[45678]*ba[123]),那麼就可以O(1)求aba^b

程式碼

#include <cstdio>
#include <iostream>

using namespace std;

long long a,p,q,k,b0,l,m,c,b,ans;
long long ab[1000006],ba[1000006];

int main(){
	cin>>a>>p>>q>>k;
	cin>>b0>>l>>m>>c;
	ab[0]=1;
	for (int i=1;i<=1000000;i++)
		ab[i]=(ab[i-1]*a)%p;
	ba[0]=1;
	for (int i=1;i<=1000000;i++)
		ba[i]=(ba[i-1]*ab[1000000])%p;
	for (int i=1;i<=q;i++){
		b=(m*b0+c)%l;
		ans^=(ab[b%1000000]*ba[b/1000000])%p;
		b0=b;
		if (i%k==0&&i>=k) cout<<ans<<endl;
	}
}