bzoj 4921: [Lydsy六月月赛]互质序列

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;
}

  

posted @ 2018-03-07 22:35  蒟蒻JHY  阅读(439)  评论(0编辑  收藏  举报