D. New Year Concert
题意:
定义一个序列是坏序列:
g
c
d
(
a
l
,
a
l
+
1
.
.
.
a
r
)
=
r
−
l
+
1
gcd(a_l,a_{l+1}...a_r) = r - l + 1
gcd(al,al+1...ar)=r−l+1,即区间
g
c
d
gcd
gcd 等于区间长度
给定一个序列
a
a
a,定义
f
(
i
)
f(i)
f(i) 是将
a
1
,
a
2
,
.
.
.
a
i
a_1,a_2,...a_i
a1,a2,...ai 这段前缀序列,变成不含坏序列的操作次数,每次操作可以选定任意一个数进行修改
思路:
g
c
d
(
)
gcd()
gcd() 里边的数不断增加时,
g
c
d
gcd
gcd 是非递增的
假设当前区间为
[
l
,
r
]
[l,r]
[l,r],此时
g
c
d
(
a
l
,
a
l
+
1
,
.
.
a
r
)
=
r
−
l
+
1
gcd(a_l,a_{l+1},..a_r)=r-l+1
gcd(al,al+1,..ar)=r−l+1 ,如果后拓展一个数,区间长度不断增加,而
g
c
d
gcd
gcd 非递增,往后不可能出现交集。
这时我们可以发现一个性质,一个端点
l
l
l,至多只存在一个端点
r
r
r 使得这个区间是坏的
这时我们可以考虑枚举左端点
l
l
l,二分右端点
r
r
r,找出所有可能的
b
a
d
bad
bad 区间,用
v
e
c
t
o
r
vector
vector 存下所有右端点对应的左端点,
可以采用
S
T
ST
ST 表预处理出区间
g
c
d
gcd
gcd 方便二分
剩下的问题是最小化修改次数,我们可以采用贪心策略
枚举右端点
i
i
i 考虑是否需要修改,对于该右端点的所有左端点,如果出现一个左端点大于上次修改的点,也就是之前的修改点没有包含在这个区间内,这时修改
a
i
a_i
ai 为大质数,答案
+
1
+1
+1,更新上一次修改的数的位置
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int Log[maxn];
int stgcd[maxn][30];
int a[maxn];
vector <int> v[maxn];
int find(int l, int r)
{
int s = Log[r - l + 1];
int d = __gcd(stgcd[l][s], stgcd[r-(1<<s)+1][s]);
return d;
}
int check(int l, int r)
{
return find(l, r) - (r - l + 1);
}
void work()
{
for(int i = 2; i <= maxn - 9; ++i) Log[i] = Log[i >> 1] + 1;
cin >> n;
for(int i = 1; i <= n; ++i){
cin >> a[i];
stgcd[i][0] = a[i];
}
for(int j = 1; j <= 21; ++j)
for(int i = 1; i + (1 << j) - 1 <= n; ++i)
stgcd[i][j] = __gcd(stgcd[i][j-1], stgcd[i+(1<<(j-1))][j-1]);
for(int i = 1; i <= n; ++i)
{
int l = i, r = n;
while(l < r)
{
int mid = (l + r + 1) >> 1;
int x = check(i, mid);
if(x >= 0) l = mid;
else r = mid - 1;
}
if(check(i, l) == 0) v[l].push_back(i);
}
int pos = -1, ans = 0;
for(int i = 1; i <= n; ++i)
{
for(auto x : v[i]){
if(x > pos){
++ans;
pos = i;
}
}
cout << ans << " ";
}
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}