zoukankan      html  css  js  c++  java
  • luoguP4931 情侣?给我烧了!(加强版)

    luogu

    普通版题解:https://www.cnblogs.com/lcxer/p/10876856.html

    在普通版里,我们考虑对于(n)对情侣,恰好(k)对是和谐的方案数是

    [ans[n][k]=inom{n}{k}A^k_n2^kg(n-k) ]

    然而这样做是(O(n^2))的,瓶颈在于如何快速求出(g(n-k))

    之前我们的做法需要用到(ans)数组,这样是无法优化的,我们换一个思路来求(g)

    假如我们已经确定了(n-1)对情侣都是乱序的方案数(g(n-1))

    那么(n)对情侣乱序可以看做选出(1)对情侣是和谐的,然后用这(1)对情侣中的一个人与其他乱序的人交换,这样得出来的一定是(n)对情侣乱序的方案,交换的方案一共是(2*2(n-1)),然后考虑将新生成的这对座位插到那(n-1)对情侣中的方案数为(n)

    这一部分的总方案数是

    [4n(n-1)*g(n-1) ]

    然而这样算的并不全,还有一种情况考虑不到:如果有两对情侣都是和谐的,他们之间互换,这种情况之前的方案是考虑不到的

    这样的方案数是多少呢?

    除去我们新加的这一组,那么我们就选(1)组出来,选出来的方案数是(n-1)

    这两组互换的方案数是(8)

    然后再将这两组插回去方案数是(n(n-1))

    这一部分的总方案数是

    [8n(n-1)(n-1)*g(n-2) ]

    可以发现这已经是所有的方案数了,如果我们多选两组出来,这两组互换一下就是第一部分的方案了,同理其他的情况都可以转化为这两种情况

    所以

    [g(n)=4n(n-1)*g(n-1)+8n(n-1)(n-1)*g(n-2) ]

    预处理出来就可以(O(1))询问了

    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=5e6+10,N=5e6,mod=998244353;
    int k,T,n,g[maxn],fac[maxn],inv[maxn],d[maxn];
    int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
    int del(int x,int y){return x-y<0?x-y+mod:x-y;}
    int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    int mi(int a,int b){
    	int ans=1;while(b){if(b&1)ans=mul(ans,a);b>>=1,a=mul(a,a);}
    	return ans;
    }
    int C(int n,int m){return mul(fac[n],mul(inv[m],inv[n-m]));}
    int A(int n,int m){return mul(fac[n],inv[n-m]);}
    int main()
    {
    	read(T);fac[0]=inv[0]=d[0]=1;
    	for(rg int i=1;i<=N;i++)fac[i]=mul(fac[i-1],i),d[i]=mul(2,d[i-1]);
    	inv[N]=mi(fac[N],mod-2);
    	for(rg int i=N-1;i;i--)inv[i]=mul(inv[i+1],i+1);
    	g[0]=1;
    	for(rg int i=1;i<=N;i++)g[i]=add(mul(i,mul(4*i-4,g[i-1])),mul(i,mul(8*(i-1),mul(i-1,g[i-2]))));
    	while(T--)read(n),read(k),printf("%d
    ",mul(C(n,k),mul(A(n,k),mul(d[k],g[n-k]))));
    }
    
  • 相关阅读:
    Android studio 一些技术添加依赖,依赖库
    第三方集成之Mob-SMSSDk-短信验证
    使用友盟第三方集成实现QQ登录
    Android 日夜间切换Demo
    Sqlite数据库添加数据以及查询数据方法
    从网络获取json数据,使用imageloader获取网络图片资源并显示在ListView上
    检测Xcode项目不用的文件与图片
    Markdown语法
    iOS动画
    OC与JS交互之WKWebView
  • 原文地址:https://www.cnblogs.com/lcxer/p/10878071.html
Copyright © 2011-2022 走看看