https://ac.nowcoder.com/acm/contest/97017/F
如果一个数组是优雅的,则满足以下条件其中之一:
1.数组长度是1。
2.对于任意一个元素$a_i$,都存在一个其他元素$a_j$,使得,$a_i|a_j 或 a_j|a_i$。
如果一个数组是好的,则它的所有连续子数组都是优雅的。
问对数组a,有多少个$x\in [1,k]$,使得数组中所有元素加上x之后,数组a是好的。
求这样的x的个数和总和
分析:
如果一个数组是好的,说明每个长度为2的子数组都是优雅的(长度大于等于2)。则说明任意两个相邻元素,其中一个能整除另外一个。
再考虑长度为3的子数组,发现如果所有长度为2的子数组是优雅的,则长度为3的子数组一定也是优雅的。所以只用考虑所有相邻元素加上x之后是另一个的倍数或因子即可。
设任意两个相邻元素为a,b,如果相等的话不用考虑,如果不相等的话:
$$a>b,(b+x)|(a+x) = (b+x)*k = (a+x),k\in N^+\\
k = \frac{a-b}{b+x} \in N^+
\\b+x是a-b的因子。(x\in [1,k])
$$
最终符合要求的x,是对所有相邻元素的取值取一个并集。
这里就可以暴力枚举了,因为1e9数量级以内,一个数的因子最多为1344个。任取两个不同的元素,求他们的因子,然后对所有因子判断一下是否对每个相邻不等元素都符合即可。1344*n的数量级
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
#define MULTI_TEST
void solve(){
int n,k;
cin>>n>>k;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
if(n==1){
ll ans = ((k+1)*k)/2;
cout<<k<<" "<<ans<<endl;
return;
}
//a-b是min(a,b)+x的倍数
set<int> fac;
int a1 = a[1];
int a2 = a[1];
for(int i=2;i<=n;i++) if(a[i]!=a[i-1]){ a2 = a[i]; break;}
if(a2==a1){
ll ans = ((k+1)*k)/2;
cout<<k<<" "<<ans<<endl;
return;
}
if(a1<a2) swap(a1,a2);
for(int i=1;i*i<=(a1-a2);i++){
if((a1-a2)%i==0){
ll fac1 = i-a2;
if(fac1>=1 && fac1<=k) fac.insert(fac1);
ll fac2 = (a1-a2)/i-a2;
if(fac2>=1 && fac2<=k) fac.insert(fac2);
}
}
ll cnt=0,ans = 0;
for(auto x:fac){
bool flag = true;
for(int i=1;i<n;i++){
if(a[i+1]==a[i]) continue;
int a1 = a[i],a2 = a[i+1];
if(a1<a2) swap(a1,a2);
if((a1-a2)%(a2+x)!=0){
flag = false;
break;
}
}
if(flag) cnt++,ans+=x;
}
cout<<cnt<<" "<<ans<<endl;
}
signed main(){
ifstream test_file("in.txt");
if (test_file) {
freopen("in.txt", "r", stdin);
freopen("output.txt", "w", stdout);
}
std::ios::sync_with_stdio(0);std::cout.tie(0);std::cin.tie(0);
int T = 1;
#ifdef MULTI_TEST
cin>>T;
#endif
while(T--){
solve();
}
return 0;
}