目录
3.对于每个对应位置,都只和第一个作差比较就够了:(传递性)
题目要求:
这道题是给个数组,划分为几个子数组,看是否有个数m,对每个数取余后,使得这些子数组完全相同。
每有一个m,ans+1。
(时间复杂度的计算可以看大佬博客Codeforces Round 919 (Div. 2) (A-D)-CSDN博客)
一些样例解释:
//第一个样例k = 1是不可以的
//1 3 1 1 3 1
//k = 6
//k = 3
//k = 2 m = 2
//k = 1 m = 2
//6 2 6 2 2 2
//k = 6
//k = 3 m = 4
//k = 2 m = 4
//k = 1 m = 4
0.总思路:
我们就是要找m嘛,直接找不好找,所以接下来的步骤就是转换m,使其有更紧密简单的关系,进而容易求解。
1,2是说出其中的关联。
3则是省去多余的比较。
4更是利用性质,把整个过程给联系起来了
1.同余定理:
两个数模完相同,那么他们的差值是这个除数的倍数
a%m == b%m ∴|a-b|%m == 0
(直接找不好找,我们可以转换。这也将前后联系起来了。)
2.所以看 a-b :
(
直观的例子:
比如 a c b d 我们分为 a c 和 b d 两组,那么要的就是 a%m == b%m,c%m == d%m。
即(a-b)%m==0,(c-d)%m==0。
即m是a-b和c-d的公约数 ——>每组对应数的差值是m的倍数 ——>公约数
m不可以是1
)
所以
若存在m使得两个区间%m后是相同的,那么这些对应数的差(的绝对值)的最大公约数不能是1,而得是m
3.对于每个对应位置,都只和第一个作差比较就够了:(传递性)
证明:
(a-b)%m == (a-c)%m == 0
说明b和c差若干个m ,即(b-c)%m == 0
(不然要遍历太多次)
4.直接对m求gcd。
m的倍数可以,m也可以(我的公约数的公约数也是我的公约数)
(原理: 7对4取余和对2取余的结果是相同的)
我们可以求出每个位置的m,几个m之间还得再进行一次gcd。
因为我的公约数的公约数也是我的公约数,而符合的约数也只会小于等于m啦,所以我们直接对m进行gcd即可
(两数相等差值为0也处理掉了,a == a,两数相等不管对谁取余都是相等的,不需要处理)
5.核心代码
for (int k = 1; k <= n-1; k++)
{
if (n % k == 0)//可等分
{
int tmp = 0;
for (int i = 0; i < k; i++)//每组
{
for (int j = i; j + k < n; j += k)
{
tmp = gcd(tmp, abs(arr[j+k]-arr[j]));
}
}
if (tmp != 1)ans++;
}
}