http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2318
problem E . Mod
TimeLimit: 1000ms Memory Limit: 100000k
Description
Kim剛剛學會C語言中的取模運算(mod)。他想要研究一下一個數字A模上一系列數後的結果是多少。幫他寫個程序驗證一下。
Input
第一行一個整數T代表數據組數。
接下來T組數據,第一行一個整數n,接下來n個數字ai
接下來一行一個整數m,接下來m個數字bi
Output
對於每個bi,輸出bi%a1%a2%...%an
Sample
Input |
Output |
1 4 10 9 5 7 5 14 8 27 11 25 |
4 3 2 1 0 |
Hint
在C語言中,A mod B 是 a%b
樣例解釋:
14%10%9%5%7=4
8%10%9%5%7=3
...
數據範圍:
1<=n<=100000
1<=m<=100000
1<=ai<=1000000000
0<=bi<=1000000000
開始以爲是用什麼高端的數論算法,想了很久沒想到,換了個姿勢,找一找規律沒想到就a了...
規律: mod[i]這個序列一定要是遞減的,而且相鄰的兩個數不能互爲倍數 ,
mod[0]是mod序列的循環節,
遞減是因爲如果前面已經MOD了一個小數,那後面這個大一點的MOD肯定對結果沒有任何影響
如果前面一個數是12,那麼緊鄰的後一個數不能是2,3,4,6,之中的任何一個數,如果是就用後面的數把12替換掉
這樣就化簡了很多mod[i], 接下來找循環節就行了,很顯然循環節就是化簡後的mod[0],
有了循環節,後面計算肯定有重複,就用map把算過的記錄一下就好了
#include <cstdio>
using namespace std;
int mod[100050];
map<int,int>ans;
int main(){
int t, n ,m ;
scanf("%d",&t);
while ( t-- ){
scanf("%d",&n);
int x,idx = 0;
scanf("%d",mod); n--;
while ( n--){
scanf("%d",&x);
if( x < mod[idx] ){
while ( mod[idx] % x == 0 ) idx--;
mod[++idx] = x;
}
}
// for (int i = 0;i < idx;++i )
// cout <<mod[i]<<" ";cout <<endl;
scanf("%d",&m);
ans.clear();
int tx;
while ( m-- ){
scanf("%d",&tx);
if ( ans.find(tx%mod[0]) != ans.end() )
printf("%d\n",ans[ tx%mod[0] ]);
else {
x = tx;
for (int i = 0 ;i <= idx;++i)
x %= mod[i];
ans[tx%mod[0]] = x;
printf("%d\n",x);
}
}
}
return 0;
}