码迷,mamicode.com
首页 > 其他好文 > 详细

luogu P4931 情侣?给我烧了!

时间:2019-02-13 09:18:05      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:ons   一半   etc   预处理   阶乘   get   turn   getch   register   

双倍经验

传送门

首先坐在一起的cp和不坐在一起的cp是相对独立的,可以分开考虑,然后方案数相乘

坐在一起的cp,方案为\(\binom{n}{k}*\binom{n}{k}*k!*2^k\).首先选出k排座位,然后选出k对cp坐下,然后这k对可以任意打乱顺序,并且每一对可以换座位

不坐在一起的cp,一开始以为就是个错排,然后错排其实是没考虑一对cp坐在同一列的情况的.考虑递推,设\(f[i]\)表示i个不坐在一起的cp的方案.首先可以选出两个不是一对cp的人,方案为\(2i*(2i-2)\),然后钦定他们坐第一排.然后考虑这两个人的另一半(严谨)

  • 另外的那两个人坐一排,一个人可以坐\(2x-2\)个位置,第二个只能坐旁边,那么剩下的人的方案就是i-2对的方案,所以总方案为\((2x-2)*f[i-2]\)

  • 他们不坐一排,那么可以先假设他们是cp(逃,然后就是i-1对的方案,即\(f[i-1]\)

然后不坐一起cp的方案为\(2i*(2i-2)*(f[i-1]+(2x-2)*f[i-2])\)

然后预处理阶乘以及逆元,还有f和2的次幂,乘起来就没了

#include<bits/stdc++.h>
#define LL long long
#define db double
#define il inline
#define re register

using namespace std;
const int N=5e6+10,mod=998244353;
il int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
il int fpow(int a,int b){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;}return an;}
int fac[N],iac[N],d[N],pw[N];
il int C(int n,int m){return (m<0||n<m)?0:1ll*fac[n]*iac[m]%mod*iac[n-m]%mod;}

int main()
{
    //fffffffffffffffffffff
    fac[0]=1;
    for(int i=1;i<=N-10;++i) fac[i]=1ll*fac[i-1]*i%mod;
    iac[N-10]=fpow(fac[N-10],mod-2);
    for(int i=N-10;i;--i) iac[i-1]=1ll*iac[i]*i%mod;
    pw[0]=1;
    for(int i=1;i<=N-10;++i) pw[i]=(pw[i-1]<<1)%mod;
    d[0]=1;
    for(int i=2;i<=N-10;++i) d[i]=1ll*2*i%mod*2*(i-1)%mod*(d[i-1]+1ll*2*(i-1)*d[i-2]%mod)%mod;
    int T=rd();
    while(T--)
    {
        int n=rd(),k=rd();
        printf("%lld\n",1ll*C(n,k)*C(n,k)%mod*fac[k]%mod*pw[k]%mod*d[n-k]%mod);
    }
    return 0;
}

luogu P4931 情侣?给我烧了!

标签:ons   一半   etc   预处理   阶乘   get   turn   getch   register   

原文地址:https://www.cnblogs.com/smyjr/p/10367958.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!