链接:Ural - 1760
题意:这道题题意很难理解,大体的意思是给三个数, a, b, n, 有两个人,第一个人把这 n 个数按顺序写在一页页纸上,每页纸写 a 个数,第二个人每页纸写 b 个数,然后要求判断有多少对数(x,y),x 和 y 对于第一个人来说是在同一页纸上的,但对于第二个人来说是在不同页上的。
思路:设第一个人的每一页第一个数为 i ,i 在第二个人的页数为 x,那么从 A(第一个人)每一页的第二个数开始找,找到第一个和 i 在 B(第二个人)中不同页的数 d,此时,d 对于它所在的 A的那一页在它前面的数,能形成的对数就是(d-i),也就是 d 在该页的偏移量,因为在该页 d 前面的数都是符合它们在 A同页,在 B不同页。接着往下找,如果目前的数 j 依然和前面的 d 在同一页,那么j 与该页前面能形成的对数也和 d 一样,如果 j 再变成 d 所在页的下一页,那么此时对于它来说,在 A的该页前面的数都能和它形成对,所以对数是它自己的偏离量,也等于 d 的偏移量加上 (j-d)。以此类推,把所有的对数加起来就是答案。因为数据比较大,所以答案要用 long long 来存。
前面解释得比较抽象,不妨看看例子吧。
首先看 a = 3,b = 4,n =10,在 A的第一页开始找,但这一页每个数在 A 中同页,在 B 中也同页,所以第一页没有。第二页中,4 在B 的第一页,5在B的第二页,所以 5 是第一个和该页第一个数在 B 中不同页的数,偏移量为 1,所以形成的对数为 1,接下来 6,6和 5 在 B 中保持同页,所以对数也是 4 的偏移量 1,然后看 8 ,8 和 7 在 B 中同页。看 9 ,9 是该页中第一个和该页第一个数在 B 中不同页的数,偏移量是 2,所以对数为 2。最后 10,只有一个数,没有。所以答案为 1 + 1 + 2 = 4.
1 4 7 10 1 5 9
2 5 8 2 6 10
3 6 9 3 7
4 8
(A) (B)
再看一个例子, a = 5,b =2,n= 10, A中第一页从 2 开始找,2 和1 同页,继续。3 和 1不同页,对数为它的偏移量 2, 然后 4 和 3 同页,所以对数也是 2,而 5 和4 不同页,所以对数也它自己的偏移量 4. 第二页的 7 对数1,8 对数 1,9 对数3,10 对数 3.最终答案为 16.
1 6 1 3 5 7 9
2 7 2 4 6 8 10
3 8 (B)
4 9
5 10
(A)
算法步骤:
步骤1:ans 保存答案,可以形成多少对数,a, b, n意义和题目相同,开始循环,i 从 0 开始,每次 +a ,所以每次 i都是 A 每页的第一个数,pos 表示 i在B 中的页数,k 代表目前应该加上的偏移量,flag 代表是否找到第一个和 i 不同页的数,cur 代表当前数的前面的数所处页数,用于判断是否出现在 B 中转移到下一页。
步骤2:对于每个 i,让 j 从 i+1 开始,直到 i+a结束,找遍该页中的数,如果该数 j 和 i 在B 中处在同一页,则 continue, 否则,判断是否是第一个和 i 不同页的数,是的话更新 cur 为 J 所处页数, k 为偏移量,flag 改变。已经不是第一个数了,则判断是否在 B 中跳转到新的一页,是则更新 k 和 cur。ans 加上符合条件的对数。
步骤3:输出 ans。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int a,b,n;
int main()
{
long long ans;
while(cin>>a>>b>>n)
{
ans = 0;
for(int i = 0;i < n;i += a)
{
int pos = i/b,k = 1,cur; // 整除以 b 就是该数所处页数
bool flag = 0;
for(int j = i+1;j < i+a && j < n;++j)
{
int p2 = j/b;
if(p2 == pos) continue;
if(!flag)
{
cur = p2;
k = j -i;
flag = 1;
}
if(p2 != cur)
{
k = j - i;
cur = p2;
}
ans += k;
}
}
cout<<ans<<endl;
}
}