• Gym102538H Horrible Cycles


    Link
    (2n)个点进行排序,使得每个左部点与前面的所有右部点都有连边,然后将其编号为([1,2n])
    对于一个环而言,假如我们只保留环中([1,x])范围内的点,那么这个环会被拆成若干条链。
    我们以此为状态进行dp,设(f_{i,j})表示只保留([1,i])范围内的点,形成(j)条链的方案数。
    显然初始状态为(f_{0,0}=1),因此考虑加入点(i)会造成什么影响。
    如果(i)是右部点,那么它和([1,i))的所有点都没有连边。如果(i)被选择,那么它会单独成一条链。
    即转移为(f_{i-1,j}+f_{i-1,j-1} ightarrow f_{i,j})
    如果(i)是左部点,那么它和([1,i))的所有右部点都有连边。如果(i)被选择,那么它会将之前的两条链合并为一条。
    即转移为(f_{i-1,j}+j(j-1)f_{i,j+1} ightarrow f_{i,j})
    还有一个转移,是(i)将之前的一条链的两段接起来形成一个环,即将(f_{i-1,1})累加进答案。
    我们需要剔除所有的二元环,即将答案减去(sumlimits_{i=1}^na_i)
    因为链是有序的,所以会将一个环计算两遍,因此最后还要将答案除以(2)

    #include<cstdio>
    #include<algorithm>
    const int N=5007,P=998244353,i2=P-P/2;
    int read(){int x;scanf("%d",&x);return x;}
    void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
    void dec(int&a,int b){a-=b,a+=a>>31&P;}
    int mul(int a,int b){return 1ll*a*b%P;}
    int a[N],f[N];
    int main()
    {
        int n=read(),ans=0;
        for(int i=1;i<=n;++i) dec(ans,a[i]=read());
        std::sort(a+1,a+n+1),f[0]=1;
        for(int i=1;i<=n;++i)
        {
    	for(int j=a[i-1]+1;j<=a[i];++j) for(int k=j;k;--k) inc(f[k],f[k-1]);
    	inc(ans,f[1]);
    	for(int j=1;j<=a[i];++j) inc(f[j-1],mul(j*(j-1),f[j]));
        }
        printf("%d",mul(ans,P-P/2));
    }
    
  • 相关阅读:
    VScode 最新eslint设置
    vue部署在二级目录
    实现网页比12像素小
    css一个很好用的hover显示
    VSCode设置
    vue发布后的一些问题
    设置cssrem,设置emmet
    js时间与时间戳之间的转换操作,返回天、小时、分,全家桶
    Error resolving template [xxx], template might not exist or might not be exist
    解决jenkins shell执行sonar-scanner提示命令存在的问题
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12668963.html
Copyright © 2020-2023  润新知