zoukankan      html  css  js  c++  java
  • 题解 洛谷P6561 [SBCOI2020] 人

    题目大意

    题目链接

    给定三个正整数(m), (a), (b)。要求在([1,2m])中选出(a)个奇数,(b)个偶数,并且选出的数两两不相邻。问有多少种选择的方案。方案数对(998244353)取模。

    (T)组测试数据。

    数据范围:(1leq a,bleq mleq 10^6)(a+bleq m)(1leq Tleq 10^6)

    本题题解

    考虑相邻的一奇一偶,也就是形式化地表述为(2i+1), (2i+2) ((0leq i<m))这两个数,它们不可能同时被选中。对于第(i)组数,如果(2i+1)(奇数)被选中,称这一组为( ext{A});如果(2i+2)(偶数)被选中,称这一组为( ext{B});如果都没有被选中,称这一组为( ext{C})。则任何一种合法的选择方案,可以被表示为一个长度为(m)( ext{ABC})串,其中有(a)( ext{A})(b)( ext{B}),和(m-a-b)( ext{C}),并且不允许出现( ext{BA})这个子串。我们相当于要求这样的( ext{ABC})串的数量。

    先不考虑( ext{A})( ext{B})( ext{C})的相对位置关系可以任意安排,它们共有(b+(m-a-b)=m-a)个,所以任意安排的方案数是({m-achoose b})

    再插入( ext{A})( ext{A})不能被插入在( ext{B})后面,除此之外其他任何位置都是可以的。考虑第(1)( ext{A}),它可以被插入在最前面,或者某个( ext{C})后面,所以有(m-a-b+1)种方案;第(2)( ext{A}),除了最前面和某个( ext{C})后面以外,还能插入在第(1)( ext{A})后面,所以有(m-a-b+2)种方案;以此类推,第(k)( ext{A})(m-a-b+k)种插入方案。同时,所有( ext{A})是本质相同的,所以还要除以(a!)。所以插入( ext{A})的总方案数就是:(frac{(m-a-b+1)cdot(m-a-b+2)cdots(m-a-b+a)}{a!}={m-bchoose a})

    因此答案就是:({m-achoose b}cdot{m-bchoose a})

    (T)次求组合数。预处理阶乘和阶乘的逆元即可。

    时间复杂度(O(m+T))

    参考代码(本代码仅供参考,建议添加读入优化):

    //problem:P6561
    #include <bits/stdc++.h>
    using namespace std;
    
    #define pb push_back
    #define mk make_pair
    #define lob lower_bound
    #define upb upper_bound
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    
    typedef unsigned int uint;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    
    template<typename T>inline void ckmax(T& x,T y){x=(y>x?y:x);}
    template<typename T>inline void ckmin(T& x,T y){x=(y<x?y:x);}
    
    const int MAXN=2e6;
    const int MOD=998244353;
    inline int mod1(int x){return x<MOD?x:x-MOD;}
    inline int mod2(int x){return x<0?x+MOD:x;}
    inline void add(int& x,int y){x=mod1(x+y);}
    inline void sub(int& x,int y){x=mod2(x-y);}
    inline int pow_mod(int x,int i){int y=1;while(i){if(i&1)y=(ll)y*x%MOD;x=(ll)x*x%MOD;i>>=1;}return y;}
    
    int fac[MAXN+5],ifac[MAXN+5];
    inline int comb(int n,int k){
    	if(n<k)return 0;
    	return (ll)fac[n]*ifac[k]%MOD*ifac[n-k]%MOD;
    }
    void facinit(int lim=MAXN){
    	fac[0]=1;
    	for(int i=1;i<=lim;++i)fac[i]=(ll)fac[i-1]*i%MOD;
    	ifac[lim]=pow_mod(fac[lim],MOD-2);
    	for(int i=lim-1;i>=0;--i)ifac[i]=(ll)ifac[i+1]*(i+1)%MOD;
    }
    
    int m,a,b;
    int main() {
    	facinit();
    	int T;cin>>T;while(T--){
    		cin>>m>>a>>b;
    		int ans = (ll)comb(m-a,b) * comb(m-b,a) % MOD;
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    ASP.NET MVC案例——————拦截器
    Windows Azure Virtual Network (10) 使用Azure Access Control List(ACL)设置客户端访问权限
    Windows Azure Storage (20) 使用Azure File实现共享文件夹
    Windows Azure HandBook (5) Azure混合云解决方案
    Windows Azure Service Bus (6) 中继(Relay On) 使用VS2013开发Service Bus Relay On
    Azure PowerShell (9) 使用PowerShell导出订阅下所有的Azure VM的Public IP和Private IP
    Windows Azure Service Bus (5) 主题(Topic) 使用VS2013开发Service Bus Topic
    Azure China (9) 在Azure China配置CDN服务
    Windows Azure Storage (19) 再谈Azure Block Blob和Page Blob
    Windows Azure HandBook (4) 分析Windows Azure如何处理Session
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/13324193.html
Copyright © 2011-2022 走看看