其他分享
首页 > 其他分享> > D. Lost Arithmetic Progression ,Codeforces Round #785 (Div. 2)

D. Lost Arithmetic Progression ,Codeforces Round #785 (Div. 2)

作者:互联网

     a1,d1,n1 分别为b首项,公差,总项数      a2,d2,n2 分别为c首项,公差,总项数 首先明确当一个等差数列是另一个等差数列的一部分时,那么前者公差一定是后者公差的倍数 先判断0的情况,当c不是b的一部分时为0,包括两种情况:                                     ①c的公差不是b的公差的倍数                                     ②c的公差是b的公差的倍数 但是b没有把c完全包括在内 故
 if (d2 % d1 != 0 || (a2 < a1 || a2 + (n2 - 1) * d2 > a1 + (n1 - 1) * d1) || (abs(a2 - a1) % d1 != 0))
    {
        cout << 0 << "\n";
        return;
    }

 

-1的情况(无限个a满足条件) :首先①②都满足,然后需要有两个“端点”将a限制在两个“端点”内。

怎样找两个端点,例如序列b,c。(c序列为括号内的元素序列) -8 -6 -4 -2 (0) 2 4 (6) 8 10 (12) 14 16 18 20 的两个“端点”为 -6 和 18 如果没有右边“端点”18序列b为: -8 -6 -4 -2 (0) 2 4 (6) 8 10 (12) 14 16 a的公差可以是d2的任意因子:所以a可能是 3 6 (后续会解释为什么是3 6) 当a的公差为6时可从右边无限延伸,因为没有18这个“端点”的限制,a的公差为3时同理。 显然左右两个“端点”分别为: a2-d2  a2+(n2-1)*d2+d2 为何两个“端点”用a可能公差的最大的公差算,因为如果用较小的公差算出来的“端点”可能限制不了较大的公差。 故,  
if ((a1 > a2 - d2 || a1 + (n1 - 1) * d1 < a2 + (n2 - 1) * d2 + d2))
{
    cout << -1 << "\n";
    return;
}
接下来就要计算除以上两种情况下的答案,假设a公差为d3。 先讨论特殊情况:d1==d2 例如序列b,c。(c序列为括号内的元素序列)  -6  (0)  (6)  (12)  18      d1==d2==6 前面明确过当一个等差数列是另一个等差数列的一部分时,那么前者公差一定是后者公差的倍数 所以d3一定是d2的因子,d3可能值:1 2 3 6  显然都满足 *所以发现如果 d1==d2 那么d3的所有可能为d2的所有因子。 具体答案如何算? 假设公差为3  a序列可能是     0 3 6 9 12     0 3 6 9 12 15  -3 0 3 6 9 12  -3 0 3 6 9 12 15  四种。   a序列所有可能可以由序列 0 3 6 9 12延伸得到 延申左边的可能情况为 可延申的数字个数(d2/d3 -1) + 1 = d2/d3 右边同理,所有情况为左右两类乘积;d2/d3 * d2/d3 。
int ans = 0;
for (int i = 1; i * i <= d2; i++)
{
       if (d2 % i == 0)
      {
        int x = (d2 / i) % MOD;
        ans = (ans + (x * x) % MOD) % MOD;
        if (i * i != d2)
            ans = (ans + (i * i) % MOD) % MOD;
     }
}

 

  如果d1!=d2 ,假设a公差为d3
 a,b 序列包含c序列 满足: d2%d3!=0 ,d3%d2!=0  d1!=d2 *那么d3 和 d1 就不能存在倍数关系,而且 d1 和 d3的 lcm 必须是d2 有一种特殊情况:d3==d2 时虽然不满足d3%d2!=0 实际与d1并无冲突 故
for (int i = 1; i * i <= d2; i++)
    {
        if (d2 % i == 0)
        {
            if (d1 % i != 0 && i % d1 != 0 && lcm(i, d1) == d2)
            {
                int x = (d2 / i) % MOD;
                ans = (ans + (x * x) % MOD) % MOD;
            }
            int y = d2 / i;
            if (i * i != d2)
            {
                if (y == d2 || y % d1 != 0 && d1 % y != 0 && lcm(y, d1) == d2)
                {
                    int x = (d2 / y) % MOD;
                    ans = (ans + (x * x) % MOD) % MOD;
                }
            }
        }
    }

代码敲完,突然想起来!

小学一道题:小明小红今天同时去看奶奶,至少多少天后两人还能同时去看望奶奶,已知小明4天看一次,小红6天看一次。

至少多少天后两人还能同时去看望奶奶 :lcm(4,6)=12。

。。。

。。。

跟这一道题如出一辙。

所以整合下来,这道题代码如下

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;

int lcm(int a, int b)
{
    return (a * b) / __gcd(a, b);
}
void solve()
{
    int a1, d1, n1;
    int a2, d2, n2;
    cin >> a1 >> d1 >> n1;
    cin >> a2 >> d2 >> n2;
    if (d2 % d1 != 0 || (a2 < a1 || a2 + (n2 - 1) * d2 > a1 + (n1 - 1) * d1) || (abs(a2 - a1) % d1 != 0))
    {
        cout << 0 << "\n";
        return;
    }
    if ((a1 > a2 - d2 || a1 + (n1 - 1) * d1 < a2 + (n2 - 1) * d2 + d2))
    {
        cout << -1 << "\n";
        return;
    }

    int ans = 0;
    for (int i = 1; i * i <= d2; i++)
    {
        if (d2 % i == 0)
        {
            if (lcm(i, d1) == d2)
            {
                int x = (d2 / i) % MOD;
                ans = (ans + (x * x) % MOD) % MOD;
            }
            int y = d2 / i;
            if (i * i != d2 && lcm(y, d1) == d2)
            {

                int x = (d2 / y) % MOD;
                ans = (ans + (x * x) % MOD) % MOD;
            }
        }
    }
    cout << ans << "\n";
}
main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    for (cin >> t; t; t--)
        solve();
}

标签:785,Lost,Progression,公差,a1,a2,d2,d3,d1
来源: https://www.cnblogs.com/yyt123/p/16217932.html