[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
#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>1,og1=__[o][w];
        if(!og1)og1=__[o][w]=ksm(G[o],(mod-1)/i);
        for(re int t,og=1,l=0;l')return;
    if(l==r) {if(l>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>1]>>1|((i&1)?len>>1:0);
    ntt(A,0),ntt(B,0);for(re int i=0;i'?g[i]:0);
    for(re int i=0;i';
    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');
    printf("%d\n",1ll*(ans?dqm(mod-1):1)*fac[n]%mod*g[n]%mod);
    return 0;
}

你可能感兴趣的:([LNR#2 D1T3] 不等关系)