1. 程式人生 > >bzoj 4921: [Lydsy六月月賽]互質序列

bzoj 4921: [Lydsy六月月賽]互質序列

gree 找到 long 期望值 max inline desc 包含 out

4921: [Lydsy六月月賽]互質序列

Time Limit: 1 Sec Memory Limit: 256 MB
Submit: 188 Solved: 110
[Submit][Status][Discuss]

Description

你知道什麽是“互質序列”嗎?那就是所有數的最大公約數恰好為1的序列。 “互質序列”非常容易找到,但是我們可以嘗試通過刪除這個序列的一個非空連續子序列來擴大它的最大公約數。 現在給定一個長度為n的序列,你需要從中刪除一個非空連續子序列,使得剩下至少2個數,令E為剩下數的最大公約數的期望值,S為合法的方案數,請計算E*S的值。因為這個值可能非常大,請對998244353取模輸出。

Input

第一行包含一個正整數n(3<=n<=100000),表示序列的長度。 第二行包含n個正整數a_1,a_2,...,a_n(1<=a_i<=10^9),分別表示序列中的每個元素。

Output

輸出一行一個整數,即E*S mod 998244353的值。

Sample Input

5
3 4 5 2 9

Sample Output

14
發現本質就是選一個前綴(可以為空)和一個後綴(可以為空),使得前綴的末尾必須在後綴的開頭的左邊且不能相鄰且前綴後綴元素個數>=2的前後綴gcd的和。 可以發現每個後綴的gcd都是a[n]的某個約數,並且gcd最多只有log種,因為每次gcd減小都伴隨著至少一個質因子的失去。
所以我們就可以寫暴力了,設r[i]為與i的後綴有相同gcd的最右後綴j,每次暴力統計就好了。 反正我是分成只有前綴(這時候不能只選a[1]),只有後綴(不能只選a[n]),還有前綴後綴都有的情況。
/**************************************************************
    Problem: 4921
    User: JYYHH
    Language: C++
    Result: Accepted
    Time:308 ms
    Memory:2460 kb
****************************************************************/
 
#include<bits/stdc++.h>
#define ll long long
#define maxn 100005
const int ha=998244353;
using namespace std;
int a[maxn],n,hz[maxn];
int r[maxn],qz=0,ans=0;
  
inline int add(int x,int y){
    x+=y;
    while(x>=ha) x-=ha;
    return x;
}
  
int gcd(int x,int y){
    return y?gcd(y,x%y):x;
}
  
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    hz[n+1]=0;
    for(int i=n;i>1;i--){
        hz[i]=gcd(a[i],hz[i+1]);
        r[i]=(hz[i]==hz[i+1]?r[i+1]:i);
         
        //後綴 
        if(i<n) ans=add(ans,hz[i]);
    }
      
    for(int i=1;i<n;i++){
        qz=gcd(qz,a[i]);
        //前綴 
        if(i>1) ans=add(ans,qz);
        //前綴+後綴 
        if(qz==1) ans=add(ans,n-i-1);
        else{
            for(int j=i+2;j<=n;j=r[j]+1){
                ans=add(ans,gcd(hz[j],qz)*(ll)(r[j]-j+1)%ha);
            }
        }
    }
      
    printf("%d\n",ans);
    return 0;
}

  

bzoj 4921: [Lydsy六月月賽]互質序列