题解:P11626 [迷宫寻路 Round 3] 七连击
george0929 · · 题解
前置知识:ST 表,二分,前缀和优化 DP,最大公约数的性质。
转化一下题意,把序列分成八段,取前七段的
有一个
考虑优化,
考虑用前缀和优化
由于右端点固定时,区间
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
void upd(int &a,int b){
b=(b%mod+mod)%mod;
a=(a+b)%mod;
}
int gcd(int a,int b){
if(b==0) return a;
return gcd(b,a%b);
}
int n,a[100005];
struct node{
int l,r,v;
};
vector<node> V[100005];
int st[100005][21];
int f[100005][8],g[100005][8];
int sumf[100005][8],sumg[100005][8];
int cost(int l,int r){
int k=__lg(r-l+1);
return gcd(st[l][k],st[r-(1<<k)+1][k]);
}
void workg(int k){
for(int i=1;i<=n;i++){
upd(g[i][k],sumg[i-1][k-1]);
upd(sumg[i][k],sumg[i-1][k]+g[i][k]);
}
}
void workf(int k){
for(int i=1;i<=n;i++){
upd(f[i][k],sumf[i-1][k-1]);
for(auto cur:V[i]){
int l=cur.l,r=cur.r,v=cur.v;
upd(f[i][k],v*(sumg[r-1][k-1]-sumg[l-2][k-1])%mod);
}
upd(sumf[i][k],sumf[i-1][k]+f[i][k]);
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
st[i][0]=a[i];
}
for(int j=1;j<=20;j++){
for(int i=1;i<=n;i++){
if(i+(1<<(j-1))>n) continue;
st[i][j]=gcd(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
}
for(int i=1;i<=n;i++){
int r=i,v=a[i];
while(r>=2){
v=gcd(v,a[r]);
int L=2,R=r,l=r;
while(L<=R){
int mid=(L+R)/2;
if(cost(mid,i)!=v){
L=mid+1;
}else{
R=mid-1;
l=mid;
}
}
V[i].push_back({l,r,v});
r=l-1;
}
}
for(int i=1;i<=n;i++){
f[i][1]=gcd(f[i-1][1],a[i]);
upd(sumf[i][1],sumf[i-1][1]+f[i][1]);
g[i][1]=1;
sumg[i][1]=i;
}
for(int k=2;k<=7;k++) workg(k);
for(int k=2;k<=7;k++) workf(k);
int ans=0;
for(int i=1;i<=n;i++){
upd(ans,f[i][7]);
}
cout<<ans<<"\n";
return 0;
}