PKUSC2018 최대 접두사와

최대 접두어와

C는 작은 알고리즘 경연 대회 매니아입니다, 작은 C 일일는 매우 어려운 문제를 충족 : 하위 섹션과 최대의 순서를 찾을 수 있습니다.

그러나이 문제를하지 않는 작은 C는 작은 C는 순서를 방해하고 최대 접두어 순서를 가지고 대답으로 무작위로 결정한다.

작은 C가 너무 정확성에 대해 상관 없어, 매우 자기 지식, 그는 완전히 잘못 자신의 연산을 알고있다, 기대 값을 얻을 솔루션에 대해 그는 단지 걱정, 이제 대답이 매우 복잡 할 수 있기 때문에 그가이 문제를 해결하는 데 도움이, 당신은 단지 곱한 응답 출력에 필요하므로 \ (N! \)(998 244 353 \) \ 값 모듈로, 분명히이 정수입니다.

주 : 접두사 최대 및 정의 : \ ([. 1, N-] \ FORALL I \에서 \) \ (. \ sum_ J {} = {I} ^ 1 a_j \) 최대.

옵션 (\ 100 \ % \) 데이터 만족 \ (1 \ 당량 N- \ 당량 20 \.) \ (\는 ^ {N-} {I가 1 =.} sum_ | A [I] |. \ 당량 10 ^ 9 \) .

문제 해결

https://www.cnblogs.com/zjp-shadow/p/9141971.html

찾기 어렵지 않다, 가장 큰 접두사 및 위치 \ (p \) 모든 접두사 뒤에 없습니다 \ (> 0 \) . 경우 (> 0 \) \ 다음 조금 뒤에 현재의 대답을 대체 할 수있는이 있어야합니다.

이 아이디어로, 우리는 각 시퀀스는 두 개의 섹션으로 나누어 져 고려할 수 있고, 분리 점은 위치입니다 \ (ρ-\) . 참고 \ (sum_s \)\ (S \) 이 상태는 모든 지점의 대수 합이다.

  1. 참고 \ (F (S) \) 대표 \ (S \) 최대 프리픽스 세트 구성과 동일 \ (sum_s \) 및 덜 엄격한 프리픽스 및 프로그램의 수. 피할 다시 계산하기 위해 여기에 덜 지정된 다른 접두사.

    만약에 그래서 \ (sum_s는> 0 \) , 우리는 단일 지점 뒤에 넣을 수 있습니다.

    \ [F (\ {U \}) \ (S) F 배 \ 향하는 화살표 F (\ {U \} \ 컵 S) \]

  2. 참고 \ (g (S) \) 대표 \ (S \) 의 모든 접두사 설정 및 배열된다는 \ (\ 당량 0 \) 프로그램의 수이다.

    만약 \ (sum_ {S \ 컵 \ {U \}} \ LEQ 0 \) , 다음 우리가 할 수있는 \ (S \)\ (U \) 위.

    \ [g (S) \ 배 g (\ {U \}) \ 향하는 화살표 g (S \ 컵 \ {U \}) \]

  3. 대답

    \ [ANS = \ sum_s sum_s \은 F 배 \ 배 g ([N] \ setminus S) \]

시간 복잡도 \ (O (2 ^ NN) \) .

CO int N=131072;
int omg[2][N],rev[N];

void NTT(poly&a,int dir){
    int lim=a.size(),len=log2(lim);
    for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
    for(int i=0;i<lim;++i)if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;j+=i<<1)for(int k=0;k<i;++k){
            int t=mul(omg[dir][N/(i<<1)*k],a[j+i+k]);
            a[j+i+k]=add(a[j+k],mod-t),a[j+k]=add(a[j+k],t);
        }
    if(dir==1){
        int ilim=fpow(lim,mod-2);
        for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
    }
}
poly operator*(poly a,poly b){
    int n=a.size()-1,m=b.size()-1;
    int lim=1<<(int)ceil(log2(n+m+1));
    a.resize(lim),NTT(a,0);
    b.resize(lim),NTT(b,0);
    for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
    NTT(a,1),a.resize(n+m+1);
    return a;
}

vector<int> a[2*N];
int tot,h[2*N],top;

IN bool cmp(int i,int j){
    return a[i].size()>a[j].size();
}
int main(){
    omg[0][0]=1,omg[0][1]=fpow(3,(mod-1)/N);
    omg[1][0]=1,omg[1][1]=fpow(omg[0][1],mod-2);
    for(int i=2;i<N;++i){
        omg[0][i]=mul(omg[0][i-1],omg[0][1]);
        omg[1][i]=mul(omg[1][i-1],omg[1][1]);
    }
    int n=read<int>(),w=read<int>();
    for(int i=2;i<=n;++i){
        int w=read<int>();
        a[++tot].resize(w+1);
        a[tot][0]=1,a[tot][w]=mod-1;
        h[++top]=tot;
    }
    make_heap(h+1,h+top+1,cmp);
    while(top>=2){
        int x=h[1];pop_heap(h+1,h+top+1,cmp),--top;
        int y=h[1];pop_heap(h+1,h+top+1,cmp),--top;
        a[++tot]=a[x]*a[y];
        h[++top]=tot,push_heap(h+1,h+top+1,cmp); // edit 1: cmp
    }
    int x=h[1],ans=0;
    for(int i=0;i<(int)a[x].size();++i)
        ans=add(ans,mul(mul(w,fpow(i+w,mod-2)),a[x][i]));
    printf("%d\n",ans);
    return 0;
}

추천

출처www.cnblogs.com/autoint/p/12143069.html