[LNR#2 D1T3] 不等关系

题目

快乐容斥。

发现直接做不是很好做,我们考虑把一些>强行钦定成<,这样我们很自然的就会想到容斥了,钦定之后序列是由数段<构成,中间由>来分隔,也就是我们填进去的数是数段递增序列;

设一共有\(m\)段连续<,段长分别为\(k_1,k_2...k_m\),我们需要把\(n\)个数填进去,使得每一段是递增的;这个方案数就是\(\binom{n}{k_1}\times \binom{n-k_1}{k_2}\times ... \times \binom{n-\sum_{i=1}^{m-1}}{k_m}\),不难发现其实就是\(\frac{n!}{\prod_{i=1}^mk_i!}\)

我们考虑在容斥的时候dp,我们发现考虑哪些<被钦定不是很好考虑,于是我们枚举哪些<没有被钦定;设\(g_i\)表示考虑了前\(i\)个位置,其中第\(i\)个位置没有被钦定的方案数,枚举上一个没有被钦定的位置\(j\),则有

\[g_i=[s_i='>'](-1)\sum_{j=0}^{i-1}[s_j='>']g_j\frac{1}{(i-j)!}\]

我们可以硬点\(s_0,s_n\)>这样便于计算,用分治ntt算出\(g_n\)之后乘上\((-1)^{\text{'<'个数}}n!\)即可。

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int mod=998244353;
const int G[2]={3,(mod+1)/3};
const int maxn=262144+5;
int len;char S[maxn];
int rev[maxn],A[maxn],B[maxn],__[2][105],pre[maxn];
int fac[maxn],ifac[maxn],g[maxn],n,m;
inline int dqm(int x) {return x<0?x+mod:x;}
inline int qm(int x) {return x>=mod?x-mod:x;}
inline int ksm(int a,int b) {
    int S=1;for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)S=1ll*S*a%mod;return S;
}
inline void ntt(int *f,int o) {
    for(re int i=0;i<len;i++)if(i<rev[i])std::swap(f[i],f[rev[i]]);
    for(re int w=0,i=2;i<=len;i<<=1,++w) {
        int ln=i>>1,og1=__[o][w];
        if(!og1)og1=__[o][w]=ksm(G[o],(mod-1)/i);
        for(re int t,og=1,l=0;l<len;l+=i,og=1)
            for(re int x=l;x<l+ln;++x) {
                t=1ll*og*f[x+ln]%mod,og=1ll*og*og1%mod;
                f[x+ln]=dqm(f[x]-t);f[x]=qm(f[x]+t);
            }
    }if(!o)return;int Inv=ksm(len,mod-2);
    for(re int i=0;i<len;i++)f[i]=1ll*f[i]*Inv%mod;
}
void cdq(int l,int r) {
    if(pre[r]==pre[l]&&S[l]!='>')return;
    if(l==r) {if(l<n&&l) g[l]=qm(mod-g[l]);return;}
    int mid=l+r>>1;cdq(l,mid);
    for(re int i=l;i<=mid;i++)A[i-l]=g[i];
    for(re int i=0;i<=r-l;i++)B[i]=ifac[i];
    len=1;while(len<=r-l+1)len<<=1;
    for(re int i=0;i<len;i++)rev[i]=rev[i>>1]>>1|((i&1)?len>>1:0);
    ntt(A,0),ntt(B,0);for(re int i=0;i<len;i++)A[i]=1ll*A[i]*B[i]%mod;
        ntt(A,1);for(re int i=mid+1;i<=r;i++)g[i]=qm(g[i]+A[i-l]),g[i]=(S[i]=='>'?g[i]:0);
    for(re int i=0;i<len;i++)A[i]=B[i]=0;cdq(mid+1,r);
}
int main() {
    scanf("%s",S+1);n=strlen(S+1)+1;S[n]='>';
    fac[0]=1;for(re int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
    ifac[n]=ksm(fac[n],mod-2);for(re int i=n-1;i>=0;--i)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
    g[0]=1;for(re int i=1;i<=n;i++)pre[i]=pre[i-1]+(S[i]=='>');
    cdq(0,n);int ans=0;for(re int i=1;i<n;i++) ans^=(S[i]=='>');
    printf("%d\n",1ll*(ans?dqm(mod-1):1)*fac[n]%mod*g[n]%mod);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/12204069.html