• 【XSY2990】树 组合数学 容斥


    题目描述

      同 Comb Avoiding Trees

      不过只用求一项。

      (n,kleq {10}^7)

    题解

      不难发现一棵 (n) 个叶子的树唯一对应了一个长度为 (2n-2) 的括号序列。

      往左儿子走对应加一个左括号,退到上一个只有左儿子的点,往右儿子走对应加一个右括号,那么合法的树一定满足:每一个前缀中左括号数量 (-) 右括号数量 (<m-1)

      求括号序列个数有一种容斥做法:把左括号视为 (1),把右括号视为 (-1)。用总方案数减掉走到 (-1) 的方案数

      每一个走到 (-1) 的方案在走第一次走到 (-1) 后把后面的括号取反,对应一个结尾走到 (-2) 的方案数。

      这道题要求不能走到 (m-1),那么还要减掉结尾走到 (2m-2) 的方案数。

      但是既走到 (-1) 又走到到 (2m-2) 的方案会被减掉两次,所以要加上结尾走到 (2m) 的方案数和结尾走到 (-2m) 的方案数。

      然后又要减掉 (0 o -1 o m-1 o -1) 的方案数和 (0 o m-1 o -1 o m-1) 的方案数。

      以此类推。

      时间复杂度:(O(n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<functional>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> pll;
    void open(const char *s){
    #ifndef ONLINE_JUDGE
    	char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
    #endif
    }
    int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
    void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
    int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
    int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
    const ll p=998244353;
    const int N=10000010;
    int n,m;
    ll fp(ll a,ll b)
    {
    	ll s=1;
    	for(;b;b>>=1,a=a*a%p)
    		if(b&1)
    			s=s*a%p;
    	return s;
    }
    int ifac[2*N];
    ll binom(int x,int y)
    {
    	return x>=y&&y>=0?(ll)ifac[y]*ifac[x-y]%p:0;
    }
    int main()
    {
    	open("c");
    	scanf("%d%d",&n,&m);
    	n--;
    	ll s=1;
    	for(int i=1;i<=2*n;i++)
    		s=s*i%p;
    	ifac[2*n]=fp(s,p-2);
    	for(int i=2*n;i>=1;i--)
    		ifac[i-1]=(ll)ifac[i]*i%p;
    	ll ans=binom(2*n,n);
    	for(int i=0;i<n;i+=m)
    	{
    		ans-=binom(2*n,n+i+1);
    		ans-=binom(2*n,n+i+m-1);
    		ans+=2*binom(2*n,n+i+m);
    	}
    	ans=(ans%p*s%p+p)%p;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    操作系统的一些琐碎知识
    # mysql _linux
    # linux GIT 配置连接
    linux maven 安装
    idea 与 git
    服务器搭建——jenkins构建后应该做什么(3)
    # 服务器搭建——jenkins搭建至构建成功(2)
    # 服务器搭建——入门踩坑 (1)
    # ajax入门(1)
    # heapsort
  • 原文地址:https://www.cnblogs.com/ywwyww/p/9178383.html
Copyright © 2020-2023  润新知