模运算的运用
不定期更新在各编程网站题目中模运算的运用
多组同余
若存在元素x,对于一数组中任意某个元素e,满足
e += k * x (k取任意整数)
则只需数组一中所有e对x同余(对x取模结果相同);
若存在有两个元素x y,对于数组一中任意某个元素e ,满足
e += ax+by(a b取任意整数)
又因为 ax+by = k * Gcd(a, b) (k取任意整数)
则只需数组一中所有e对Gcd(a, b)同余(对Gcd(a, b)取模结果相同);
题目来源:·计蒜客·两个数组
算法思想
- 类推下去
则只需 数组一中所有e对Gcd(数组二所有元素)同余1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42int Gcd(int a, int b)
{
if(!b)
return a;
return Gcd(b, a%b);
}
int main()
{
int n;
scanf("%d", &n);
while(n--)
{
int len1, len2;
cin >> len1 >> len2;
for(int i = 0; i < len1; ++i)
scanf("%d", &a[i]);
int gcd;
for(int i = 0; i < len2; ++i)
{
scanf("%d", &b[i]);
if(i == 0)
gcd = b[i];
else
gcd = Gcd(gcd, b[i]);
}
// cout << gcd << endl;
int flag = 0;
for(int i = 1; i < len1; ++i)
{
if(a[i-1]%gcd != a[i]%gcd)
{
flag = 1;
break;
}
}
if(flag)
cout << "No" <<endl;
else
cout << "Yes" <<endl;
}
return 0;
}
同余方程(模线性方程)性质
若 ax = b(mod n)
则 (a-b)%n = 0, a%n == b%n;
a、b可运用于两个前缀和
题目来源·蓝桥·k倍区间
算法思想
- 前缀和 + 同余
b[i]记录a[i]前缀和,子区间则可用b[i]-b[j]表示(0 <= j < i)
满足k倍区间及 (b[i]-b[j])%k==0
于是很容易有以下代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17void solve()
{
for(int i = 0; i < n; ++i)
{
b[i+1] = b[i] + a[i]; //前缀和
}
int sum = 0;
for(int i = 0; i < n; ++i)
{
for(int j = i; j < n; ++j)
{
if((b[j+1] - b[i])%k == 0)
++sum;
}
}
cout << sum <<endl;
}
显然n的平方复杂度会超时
- 优化的思想
k倍区间的个数即求多少组b[i]、b[j]满足(b[i]-b[j])%k==0
同余性质得b[i]%k == b[j]%k
对于样例
Output:
5 2
1 2 3 4 5
Input:
6
(一)得到前缀和b[] 1 3 6 10 15
(二)对 b[i]%k 得到0 1 1 0 0 1(加了个0,特殊处理b[i]%k==0的情况)1的个数为3,0的个数为3
结果有多少组呢? C23 + C23 = 6。
最终优化代码
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!