机房测试5:silhouette(组合数+递推)

Posted mowanying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机房测试5:silhouette(组合数+递推)相关的知识,希望对你有一定的参考价值。

题目:

技术图片

 

 技术图片

 

 分析:

这道题是真的难)(声明:这位大佬的题解下多做了说明,图片来源也是他的博客。

首先我们要发现一些小规律:

1.将A和B排序之后并不影响答案

证明:不管哪一列排序放到了哪里,那一列的最大值都应该是Ai。

2.A的最大一定等于B的最大:

很显然,如果不等于,那么最大值放在哪里都不合法。

3.将A和B数组按从小到大的顺序排序后,会变成这种矩形:

技术图片

 

 定义f[ i ]为至少有i行不满足,定义至少的原因:两两行之间不会受影响

显然最后我们要求的是恰好有0行不满足,即至少有0行不满足-至少有1行不满足,但因为至少有一行不满足中包含了至少有两行不满足,所以要加上,有加多了至少有三行不满足的情况,以此类推,用容斥原理计算答案。

先推S1的情况,再在S1的基础上得到S2的公式。

公式的解释他写的太好了,这里就不再阐述。

技术图片
#include<bits/stdc++.h>
using namespace std;
#define ri register int
#define ll long long
#define N 100005
const ll mod = 1e9+7;
ll a[N],b[N],s[N<<1],invfac[N],fac[N];
int read()

    int x=0,fl=1; char ch=getchar();
    while(ch<0||ch>9)  if(ch==-) fl=-1; ch=getchar(); 
    while(ch<=9&&ch>=0) x=x*10+ch-0,ch=getchar();
    return fl*x;

ll quick_pow(ll a,ll k)

    ll ans=1;
    while(k)  if(k&1) ans=ans*a%mod; a=a*a%mod; k>>=1; 
    return ans;

void init(int n)

    fac[0]=1;
    for(ll i=1;i<=n;++i) fac[i]=fac[i-1]*i%mod;
    invfac[n]=quick_pow(fac[n],mod-2);
    for(ll i=n;i>=1;--i) invfac[i-1]=invfac[i]*i%mod;

ll C(ll m,ll n)

    return fac[n]*invfac[m]%mod *invfac[n-m] %mod;

ll calc(ll a,ll b,ll c,ll d,ll ss)

    ll ret=0;
    for(ll i=0;i<=a;++i)
        ll tmp=C(i,a)* quick_pow(( quick_pow(ss,i) * ( quick_pow(ss+1,a+c-i) - quick_pow(ss,a+c-i) +mod) %mod),b) %mod;
        tmp=tmp * quick_pow(( quick_pow(ss,i) * quick_pow(ss+1,a-i) %mod ),d) %mod;
        if(i&1) ret=(ret-tmp+mod)%mod;
        else ret=(ret+tmp)%mod;
    
    return ret;

int main()

    freopen("silhouette.in","r",stdin);
    freopen("silhouette.out","w",stdout);
    int n=read(),cnt=0;
    for(ri i=1;i<=n;++i) a[i]=read(),s[++cnt]=a[i]; 
    for(ri i=1;i<=n;++i) b[i]=read(),s[++cnt]=b[i];
    sort(a+1,a+1+n);
    sort(b+1,b+1+n);
    if(a[n]!=b[n])  printf("0\\n"); return 0; 
    sort(s+1,s+1+cnt);
    int num=unique(s+1,s+1+2*n)-s-1;
    int na=n,nb=n,pa=n+1,pb=n+1;
    init(n);
    ll ans=1;
    for(ri i=num;i>=1;--i)
        while(na-1 && a[na-1]==s[i]) na--;
        while(nb-1 && b[nb-1]==s[i]) nb--;
        ans=ans* calc( pa-na,pb-nb,n-pa+1,n-pb+1,s[i] ) %mod;
        pa=na; pb=nb;
    
    printf("%lld\\n",ans);

/*
2
1 2
2 1
*/
View Code

 

以上是关于机房测试5:silhouette(组合数+递推)的主要内容,如果未能解决你的问题,请参考以下文章

[NOIP2016提高组]组合数问题

组合数与除法逆元,阶乘逆元递推

洛谷2822 组合数问题(递推)

递推递归组合数,汉诺塔,回文数问题(java)

[NOIP2016]组合数问题 17.5.21 40分

AcWing 885. 求组合数 I(递推式预处理)