zoukankan      html  css  js  c++  java
  • AT4119[ARC096C]Everything on It【斯特林数,容斥】

    正题

    题目链接:https://www.luogu.com.cn/problem/AT4119


    题目大意

    一个集合\(S=\{k\in[1,n]\cup N\}\),它的所有子集作为元素组成的集合中要求满足每一个数字的出现之和不小于\(2\),求方案数对\(P\)取模。

    \(1\leq n\leq 3000,P\in[10^8,10^{9}+9]\cup Pri\)


    解题思路

    考虑至少\(i\)个数选择次数不超过\(1\),那么这个方案的容斥系数就是\((-1)^i\)

    考虑怎么求这个方案,我们可以先不要被限制了的数,然后再将这些被限制了的数丢进被选出了的集合中。设有\(j\)个集合包含被限制了的数,那么丢进这些集合的方案就是\(\begin{Bmatrix} i+1\\j+1 \end{Bmatrix}\)(一个数字可以选择不丢所以开一个新的集合表示这个集合内的数不使用),然后剩下的数随意的选入这些集合中就是\((2^{n-i})^j\)
    那么答案出来了

    \[\sum_{i=0}^n(-1)^i2^{2^{n-i}}\binom{n}{i}\sum_{j=0}^i\begin{Bmatrix}i+1\\ j+1\end{Bmatrix}(2^{n-i})^j \]

    直接预处理斯特林数计算就好了,时间复杂度\(O(n^2)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll N=3100;
    ll n,P,s[N][N],fac[N],ans;
    ll power(ll x,ll b,ll p=P){
    	ll ans=1;
    	while(b){
    		if(b&1)ans=ans*x%p;
    		x=x*x%p;b>>=1;
    	}
    	return ans;
    }
    ll C(ll n,ll m)
    {return fac[n]*power(fac[m],P-2)%P*power(fac[n-m],P-2)%P;}
    signed main()
    {
    	scanf("%lld%lld",&n,&P);s[0][0]=fac[0]=1;
    	for(ll i=1;i<=n;i++)fac[i]=fac[i-1]*i%P;
    	for(ll i=1;i<=n+1;i++)
    		for(ll j=1;j<=i;j++)
    			s[i][j]=(s[i-1][j-1]+j*s[i-1][j]%P)%P;
    	for(ll i=0;i<=n;i++){
    		ll sum=0,tmp=power(2,power(2,n-i,P-1));
    		if(i&1)tmp=P-tmp;tmp=tmp*C(n,i)%P;
     		for(ll j=0,z=1,p=power(2,n-i);j<=i;j++,z=z*p%P)
    			(sum+=s[i+1][j+1]*z%P)%=P;
    		(ans+=sum*tmp)%=P;
    	}
    	printf("%lld\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    Flink核心技术
    Flink学习问题和答案
    Spark知识点总结
    Scala知识点总结
    Spark测试题
    Hadoop概念试题
    IntelliJ IDEA 2019 快捷键终极大全
    Linux入门
    javaSe知识点总结
    Data
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14463749.html
Copyright © 2011-2022 走看看