[LOJ6433] [PKUSC2018] 最大前綴和

題目連接

LOJ:https://loj.ac/problem/6433c++

Solution

注意到最大前綴要知足什麼性質,假設序列\(a[1..n]\)的最大前綴是\(s_x\),那麼顯然要知足全部\(x\)結尾的後綴和都爲正,且全部\(x\)開頭的前綴和都爲負,\(0\)的狀況不影響。git

有了這個轉化以後就好作了,直接狀壓,設\(g[s]\)爲選了\(s\)這些數,能構成多少種序列,使得全部前綴都爲負或\(0\)ui

轉移直接暴力枚舉當前哪個填最後一位就行了。spa

\(f[s]\)表示選了\(s\)這些數,能構成多少種序列使得除了整個序列之外全部後綴都爲正,轉移和上面相似。code

而後統計答案直接乘起來就行了。get

複雜度\(O(2^n\cdot n)\)it

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double
#define ll long long 

#define pii pair<int,int >
#define vec vector<int >

#define pb push_back
#define mp make_pair
#define fr first
#define sc second

#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) 

const int maxn = (1<<20)+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 998244353;

int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
int del(int x,int y) {return x-y<0?x-y+mod:x-y;}
int mul(int x,int y) {return 1ll*x*y-1ll*x*y/mod*mod;}

int s[maxn],f[maxn],g[maxn],a[22],n,all,ans;

int main() {
    read(n);FOR(i,0,n-1) read(a[i]);all=1<<n,all--;
    FOR(i,1,all) s[i]=a[__builtin_ctz(i)]+s[i^(i&-i)];g[0]=1;
    FOR(i,1,all) if(s[i]<=0) FOR(j,0,n-1) if((i>>j)&1) g[i]=add(g[i],g[i^(1<<j)]);
    FOR(i,0,n-1) f[1<<i]=1;
    FOR(i,1,all) {
        if(s[i]>0) FOR(j,0,n-1) if(!((i>>j)&1)) f[i^(1<<j)]=add(f[i^(1<<j)],f[i]);
        ans=add(ans,mul(s[i]%mod+mod,mul(f[i],g[all-i])));
    }write(ans);
    return 0;
}
相關文章
相關標籤/搜索