Codeforce Round #785 (Div 2)D题解
CF题目链接(你的小宝贝又来咯)
题意:
给你两个等差数列的:首项,公差,项数(长度)。给定 数列 B B B 和数列 C C C .问有多少个满足条件的数列 A A A,其中数列 A A A 是 数列 B B B 和 数列 C C C 的交集,如果数列 A A A有无穷多个,则输出 − 1 -1 −1 。
思路:
首先定义数列A的为 { s a , a . l a . e a } \{sa,a.la.ea\} {sa,a.la.ea},分别表示{ 首项,公差,项数(长度),尾项 } ,数列 B B B,和数列 C C C同理分别为 { s b , b , l b , e b } \{sb,b,lb,eb\} {sb,b,lb,eb}, { s c , c , l c , e c } \{sc,c,lc,ec\} {sc,c,lc,ec}那么我们可以得到一个小结论,即 { c = l c m ( a , b ) } \{c=lcm(a,b)\} {c=lcm(a,b)} .就是说如果有交集,那么一定大于等于两者的 l c m lcm lcm(等差数列知识?梦回高中?)
1.判断是否可以有这样的数列 A A A
(1).一个最简单的情况直接判断数列 C C C 是不是都在数列 B B B中出现过(交集最基本性质不需要过多赘述吧);
(2).必定符合 { s b ⩽ s c ⩽ e c ⩽ e b } \{sb\leqslant sc\leqslant ec\leqslant eb\} {sb⩽sc⩽ec⩽eb},因为 C ⊆ B C\subseteq B C⊆B;
(3). c % b = = 0 c\%b==0 c%b==0,因为 c = l c m ( d a , d b ) c=lcm(da,db) c=lcm(da,db) ;
(4). 判断数列
B
B
B和数列
C
C
C的首项是否满足条件,
(
s
c
−
s
b
)
%
b
=
=
0
(sc - sb)\%b==0
(sc−sb)%b==0,
d
c
dc
dc应该是
d
b
db
db倍数,这样才可有保证数列
C
C
C是数列
B
B
B与数列
A
A
A的交集!
(如果不满足上述条件,显然方案数为
0
0
0 !)
2.计算可行的方案数
(1)首先来判断有无数个的情况
如果数列
C
C
C 的首项的前一项小于数列
B
B
B的首项,那么此时数列
A
A
A的首项可以无限的向左边扩展,也就是方案数为无穷的情况,此时输出
−
1
-1
−1即可;
例如下图:
(2).计算有穷个的情况
同样先上图(嘿嘿!酱紫贴心)
(绿色部分为可以拓展的自由部分)
步骤:
分析可得只要我们确定数列的
A
A
A的公差
a
a
a就可以通过计算获得上图绿色的拓展部分的全部信息。显然数列
A
A
A可以分别向左右扩展
c
a
\frac{c}{a}
ac 个,那么总排列组合的方案数就是
c
a
∗
c
a
\frac{c}{a}*\frac{c}{a}
ac∗ac, 那么怎么确定
a
a
a呢,我们可以通过枚举
c
c
c 的因子,来枚举
a
a
a ,即可以求最终解!!
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define tententen ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);
const int N = 1e5 + 5;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const int mod=1e9+7;
const int SIZE=4e4;
auto pal = [](string s){//判断回文串
reverse(s.begin(), s.end());
return s;
};
vector<int>v;
ll sb,eb,b,lb;//首项 尾项 公差 长度
ll sc,ec,c,lc;
ll lcm(ll a,ll b){
return a/__gcd(a,b)*b;
}
void solve() {
cin >> sb >> b >> lb >> sc >> c >> lc;
eb = sb + b * (lb - 1);
ec = sc + c * (lc - 1);
if (!(sb <= sc && ec <= eb) || (sc - sb) % b != 0|| c % b != 0 ) {
cout << 0 << endl;
return;
}
if (sc - c < sb || ec + c > eb) {
cout << -1 << endl;//无穷个的情况
return;
}
ll ans = 0;
for (ll i = 1; i * i <= c; ++i) {//枚举A的公差
if (c % i == 0) { //如果满足条件
if (lcm(i, b) == c) {
ans = (ans + (c / i) * (c / i)) % mod;
}
if (c / i != i && lcm(c / i, b) == c) {
ans = (ans + i * i) % mod;
}
}
}
cout << ans << endl;
}
int main() {
tententen;
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}