【JZOJ4586】Ned 的难题

来源:互联网 发布:林清轩芦荟胶 知乎 编辑:程序博客网 时间:2024/04/28 04:05

Description

这里写图片描述

Solution

其实这题是有一个有点暴力方法可以过的,而且速度还快,但是是针对题目贪心,速度当然比正解快。但是我们要为了学知识而做题,并不是为了做题而做题
对于每个数分解质因数,因为是乘法,所以每个质数在区间中的贡献是xmin(y),所以我们用数组fl[i][j]和fr[i][j]来计算每个数的第j个质因数的向左向右贡献区间(保证这段区间的min(y)就是当前这个a[i]的x分解出的次数)。
然后转移显然。
假如算xy,y很大怎么办。参见指数取模。

Code

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int mo=1000000009,maxn=100005;int i,j,l,t,k,n,m,x,o,a[maxn];int fl[maxn][10],fr[maxn][10],f[maxn][10],ci[maxn][10],da,p[maxn],b[maxn];bool bz[maxn*100];ll ans;ll qsm(ll x,ll y){    ll z=1;    while(y){        if(y&1)z=z*x%mo;        x=x*x%mo;        y=y/2;    }    return z;}bool pan(int x,int y,int z){    if(!x)return 0;int o=0;    while(x%y==0)x/=y,o++;    if(o>=z)return 1;return 0;}int find(int x,int y){int i;fo(i,1,f[x][0])if(f[x][i]==y)return i;}int main(){    freopen("ned.in","r",stdin);    freopen("ned.out","w",stdout);    scanf("%d",&n);    fo(i,1,n)scanf("%d",&a[i]),da=max(da,a[i]);    fo(i,2,da){        if(!bz[i])p[++p[0]]=i;        fo(j,1,p[0]){            if(i*p[j]>da)break;bz[i*p[j]]=1;            if(!(i%p[j]))break;        }    }    fo(x,1,n){        t=a[x];        fo(i,1,p[0]){            if(p[i]>sqrt(a[x])+1)break;if(t<p[i])break;            if(!(t%p[i])){                f[x][++f[x][0]]=p[i];                while(!(t%p[i]))t/=p[i],++ci[x][f[x][0]];            }        }        if (t>1)f[x][++f[x][0]]=t,ci[x][f[x][0]]=1;    }    ans=1;    fo(i,1,n)fo(j,1,f[i][0]){        o=i-1;        while(pan(a[o],f[i][j],ci[i][j]))o=fl[o][find(o,f[i][j])];        fl[i][j]=o;    }    fod(i,n,1)fo(j,1,f[i][0]){        o=i+1;        while(pan(a[o],f[i][j],ci[i][j]+1))o=fr[o][find(o,f[i][j])];        fr[i][j]=o;    }    fo(i,1,n)fo(j,1,f[i][0])ans=ans*qsm(f[i][j],(ll)ci[i][j]*(i-fl[i][j])%(mo-1)*(fr[i][j]-i)%(mo-1))%mo;    printf("%lld\n",ans);}
1 0
原创粉丝点击