• 【BZOJ4402】Claris的剑(组合数学)


    点此看题面

    大致题意: 规定一个序列是合法序列当且仅当它满足:①每个元素都是正整数且不能超过一个定值(M)。②相邻两个元素的差的绝对值必须是(1)。③第一个元素必须是(1)。求有多少个长度不超过(N)的本质不同的合法序列。(此处本质不同定义为,至少存在一个元素,在两个序列中出现次数不一样)

    前言

    我觉得我完蛋了,不光文化课做题总是看错题目,现在连做信息题都看漏了题目。

    我居然没有看到这道题中关于本质不同的特殊定义,结果去推坐标系走路的式子推了半天......

    思路

    考虑对于若干本质相同的序列,如果我们设最大值为(Mx),则我们可以给它一个唯一表示法,形如:

    1 (2 1) (2 1) ... (2 1) 2 (3 2) (3 2) ... (Mx Mx-1) Mx
    1 (2 1) (2 1) ... (2 1) 2 (3 2) (3 2) ... (Mx Mx-1) Mx Mx-1 (Mx≠1)
    

    也就可以看作是在序列(1,2,...,Mx)中插入若干对数字,显然可以用隔板法计算方案数。

    注意长度是不超过(N),所以我们把剩余(N-Mx)个元素(第二种情况下是(N-Mx-1)个元素)划分成(Mx)组(每组个数都必须是偶数,因为要成对)。

    (Mx-1)组中第(i)组表示把这组元素放在(i)(i+1)之间,第(Mx)组表示不放入序列中,这样就不重不漏了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 2000000
    #define C(n,m) (1LL*Fac[n]*IFac[m]%X*IFac[(n)-(m)]%X)//组合数
    #define S(x,y) C((x)+(y)-1,(y)-1)//隔板法,计算把x个元素分成y组的方案数
    #define X 1000000007
    using namespace std;
    int n,m,Fac[N+5],IFac[N+5];
    I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    int main()
    {
    	RI i,ans=0;scanf("%d%d",&n,&m),m>n&&(m=n);//将m向n取min
    	for(Fac[0]=i=1;i<=n;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理
    	for(IFac[n]=Qpow(Fac[n],X-2),i=n-1;~i;--i) IFac[i]=1LL*IFac[i+1]*(i+1)%X;//预处理
    	for(i=1;i<=m;++i) ans=(S(n-i>>1,i)+ans)%X,i^1&&(ans=(S(n-i-1>>1,i)+ans)%X);//枚举最大值计算两种方案,个数折半表示每两个元素成一对
    	return printf("%d",ans),0;
    }
    
  • 相关阅读:
    kbmmw 5.14.00 发布
    关于C++ auto使用要注意的一点
    git设置socks5代理
    电子书分享网站
    spring cache相关
    intellij idea开启debug热加载/热部署
    git 多次commit合并成一次提交
    es feature一览
    数据中台
    Java Agent
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4402.html
Copyright © 2020-2023  润新知