同余: ,当且仅当 即a,b模m同余。
同余问题基础定理:
设a,b,c,d是整数,m是正整数,如果 , ,有: ,。
同余的对称性:
同余的传递性:if a,b and c are integers with
推导:
http://poj.org/problem?id=2115
取模mod和取余%的区别:前者的结果符号和mod后的数字一样,后者的结果符号和%前的数字一样。
例如:-8%7=-1 (计算机程序直接输出-1)
-8 mod 7= 6
8%-7=1
8 mod -7=-6
简单的模同余问题:poj C Looooops(同余方程)
大意:问for (variable = A; variable != B; variable += C)statement; 的A,B,C在mod(2^k)下经过几次能执行完,不能满足终止退奥简单的话就输出forever.
由题意可以列出等式:
拓展欧几里得求出最小的执行次数x。
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
void exgcd(LL a,LL b,LL &d,LL &x,LL &y){
if(b==0){
x=1; y=0; d=a;
return ;
}
exgcd(b,a%b,d,y,x);
y=y-(a/b)*x;
}
int main()
{
//freopen("cin.txt","r",stdin);
LL a,b,c,k;
while((cin>>a>>b>>c>>k)&&(a+b+c+k)){
LL aa=c,bb=(LL)1<<k,cc=b-a,d,x,y; //1必须先转化过来
exgcd(aa,bb,d,x,y);
bool has=1;
if(cc%d) has=0;
x=(x+bb)%bb;
x=x*(cc/d);
LL t=bb/d;
x=(x%t+t)%t; //运算次数不超过bb/d次,不然会超过1<<k。
if(!has) puts("FOREVER");
else printf("%lld\n",x);
}
return 0;
}
http://poj.org/problem?id=2769
pku 2769 Reduced ID Numbers(同余)
核心语句: For each group, she wants to find the smallest positive integer m, such that within the group all SINs reduced modulo m are unique.
Sample Input
2
1
124866
3
124866
111111
987651
Sample Output
1
8
注意本题可能超时的部分,要巧妙的清空数据hash思想,不能直接用memset。TLE ||-_-
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1e6+5;
int a[305];
bool f[maxn];
int main()
{
//freopen("cin.txt","r",stdin);
int t,n;
cin>>t;
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
if(n==1) { puts("1"); continue ;}
int k;
for(k=2;;k++){
bool find=1;
memset(f,0,sizeof(f));
for(int i=0;i<n;i++){
if(f[a[i]%k]){ find=0; break; }
f[a[i]%k]=1;
}
if(find) break;
}
printf("%d\n",k);
}
return 0;
}
修改后:
#include <iostream>
#include <cstdio>
#include <cstring> //直接使用memset超时。
using namespace std;
const int maxn=1e6+5;
int a[305];
int que[305],top;
bool f[maxn];
void clear(){
for(int i=0;i<top;i++){
f[que[i]]=0;
}
}
int main()
{
//freopen("cin.txt","r",stdin);
int t,n;
cin>>t;
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int k;
for(k=1;;k++){
bool find=1;
//memset(f,0,sizeof(f));
clear();
top=0;
for(int i=0;i<n;i++){
if(f[a[i]%k]){ find=0; break; }
que[top++]=a[i]%k;
f[a[i]%k]=1;
}
if(find) break;
}
printf("%d\n",k);
}
return 0;
}