[ICPC 2024 Chengdu R] Good Partitions题解
P15080 [ICPC 2024 Chengdu R] Good Partitions
题目描述
Lawliet 拥有一个长度为 nnn 的数字序列 a1,a2,…,ana_1, a_2, \ldots, a_na1,a2,…,an,他希望知道「好数字」的个数。
定义一个整数 kkk 是「好数字」,如果它满足以下条件:
- 1≤k≤n1 \leq k \leq n1≤k≤n;
- 将序列 aaa 依据 kkk 按照以下划分方法分成若干份后,每一份序列都是单调不降的。
划分方法为:
- 将序列 aaa 分成 ⌈nk⌉\lceil \frac{n}{k} \rceil⌈kn⌉ 份;
- 对于第 iii 份(1≤i≤⌈nk⌉−11 \leq i \leq \lceil \frac{n}{k} \rceil - 11≤i≤⌈kn⌉−1),包含的元素是 a(i−1)×k+1,a(i−1)×k+2,…,ai×ka_{(i - 1) \times k + 1}, a_{(i - 1) \times k + 2}, \ldots, a_{i \times k}a(i−1)×k+1,a(i−1)×k+2,…,ai×k;
- 对于第 ⌈nk⌉\lceil \frac{n}{k} \rceil⌈kn⌉ 份,包含的元素是 a(⌈nk⌉−1)×k+1,…,ana_{(\lceil \frac{n}{k} \rceil - 1) \times k + 1}, \ldots, a_na(⌈kn⌉−1)×k+1,…,an。
Lawliet 认为这个问题太过简单了,于是他会进行 qqq 次修改,每次修改会给出两个正整数 ppp 和 vvv,然后将 apa_pap 的数值修改为 vvv。
Lawliet 需要你帮助计算,对于未进行任何修改前以及序列 aaa 每次修改后,满足上述条件的「好数字」的个数。
输入格式
第一行包含一个整数 ttt(1≤t≤101\le t\le 101≤t≤10),代表测试组数。
对于每组测试数据,第一行包含两个整数 nnn(1≤n≤2⋅1051 \le n \le 2 \cdot 10^51≤n≤2⋅105)和 qqq(1≤q≤2⋅1051 \le q \le 2 \cdot 10^51≤q≤2⋅105),分别表示序列的长度和修改次数。
第二行包含 nnn 个整数,表示序列 a1,a2,…,ana_1, a_2, \ldots, a_na1,a2,…,an(1≤ai≤2⋅1091\le a_i\le 2\cdot 10^91≤ai≤2⋅109)。
接下来的 qqq 行,每行包含两个整数 ppp(1≤p≤n1 \le p \le n1≤p≤n)和 vvv(1≤v≤2⋅1091 \le v \le 2 \cdot 10^91≤v≤2⋅109),表示将序列中的第 ppp 个位置的元素修改为 vvv。
单个测试点中 nnn 之和与 qqq 之和均不超过 2⋅1052\cdot 10^52⋅105。
输出格式
对于每组测试数据,输出 q+1q + 1q+1 行,分别代表未进行任何修改前以及序列 aaa 每次修改后,序列中的「好数字」的个数。
输入输出样例 #1
输入 #1
1
5 2
4 3 2 6 1
2 5
3 5
输出 #1
1
2
3
思路
可以发现,值为上升的所有段的gcd,线段树维护即可。
代码见下
#include<bits/stdc++.h>
using namespace std;
int t,n,q,a[200005],pp,uu,te[800005],d[200005];
inline int gcd(int a,int b){
if(a==0||b==0){
return max(a,b);
}
else{
return __gcd(a,b);
}
}
inline void bu(int a1,int l,int r){
if(l==r){
if(a[l]>=a[l+1]+1){
te[a1]=l;
}
else{
te[a1]=0;
}
return ;
}
int mid=(l+r)/2;
bu(a1*2,l,mid);
bu(a1*2+1,mid+1,r);
te[a1]=gcd(te[a1*2],te[a1*2+1]);
return ;
}
inline void ci(int a1,int l,int r,int x,int v){
if(l>=x&&r<=x){
te[a1]=v;
return ;
}
int mid=(l+r)/2;
if(x<=mid){
ci(a1*2,l,mid,x,v);
}
else{
ci(a1*2+1,mid+1,r,x,v);
}
te[a1]=gcd(te[a1*2],te[a1*2+1]);
return ;
}
int main(){
cin>>t;
for(int i=1;i<=200000;i++){
for(int j=1;j*j<=i;j++){
if(i%j==0){
d[i]++;
if(j*j!=i){
d[i]++;
}
}
}
}
while(t--){
cin>>n>>q;
d[0]=n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
if(n==1){
cout<<1<<'\n';
while(q--){
cin>>pp>>uu;
cout<<1<<'\n';
}
continue;
}
bu(1,1,n-1);
cout<<d[te[1]]<<endl;
while(q--){
cin>>pp>>uu;
if(pp>=2&&a[pp-1]>=a[pp]+1&&a[pp-1]<=uu){
ci(1,1,n-1,pp-1,0);
}
if(pp<=n-1&&a[pp]>=a[pp+1]+1&&a[pp+1]>=uu){
ci(1,1,n-1,pp,0);
}
if(pp>=2&&a[pp-1]<=a[pp]&&a[pp-1]>=uu+1){
ci(1,1,n-1,pp-1,pp-1);
}
if(pp<=n-1&&a[pp]<=a[pp+1]&&a[pp+1]<=uu-1){
ci(1,1,n-1,pp,pp);
}
a[pp]=uu;
cout<<d[te[1]]<<"\n";
}
}
return 0;
}

浙公网安备 33010602011771号