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;
}