• 「JLOI / SHOI2016」成绩比较


    「JLOI / SHOI2016」成绩比较

    传送门

    Loj

    题解

    首先考虑可以分成两个部分计算,即人数和分数.

    1. 人数的计算:

    很明显可以容斥,设(f_{i})表示至少吊打(i)个人,那么有:

    [egin{align} f_{i}&=inom{n-1}{i}prod_{j=1}^minom{r_j-1}{n-i-1} \ ans&=sum_{i=k}^nf_iinom{i}{k}-1^{i-k} end{align} ]

    此时容斥系数不为(pm 1).

    2. 分数的计算:

    考虑单独计算一科的分数,为:

    [egin{align} ans_i&=sum_{j=1}^{u_i}j^{n-r_i}{(u_i-j)}^{r_i-1} \ &=sum_{j=1}^{u_i}j^{n-r_i}sum_{k=0}^{r_i-1}-1^ku_i^{r_i-1-k}j^{k}inom{r_i-1}{k} \ &=sum_{j=1}^{u_i}sum_{k=0}^{r_i-1}-1^ku_i^{r_i-1-k}j^{n-r_i+k}inom{r_i-1}{k} \ &=sum_{k=0}^{r_i-1}-1^kinom{r_i-1}{k}u_i^{r_i-1-k}sum_{j=1}^{u_i}j^{n-r_i+k} end{align} ]

    前面的直接枚举,后面的自然数幂和用第二类斯特林数算即可.

    [sum_{i=1}^ni^k=sum_{j=0}^kegin{Bmatrix}k\jend{Bmatrix}frac{(n+1)^{underline {j+1}}}{j+1} ]

    代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define REP(a,b,c) for(int a=b;a<=c;a++)
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    typedef pair<int,int> pii;
    #define mp make_pair
    inline int gi()
    {
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=210,Mod=1e9+7;
    int n,m,k,u[N],r[N];
    int c[N][N],S[N][N];
    int qpow(int a,int b){int ret=1;while(b){if(b&1)ret=1ll*ret*a%Mod;b>>=1;a=1ll*a*a%Mod;}return ret;}
    int calc(int n,int k)
    {
    	int down=1,ret=0;
    	for(int j=0;j<=k;j++)
    	{
    		down=1ll*down*(n+1-j)%Mod;
    		ret=(ret+1ll*down*S[k][j]%Mod*qpow(j+1,Mod-2)%Mod)%Mod;
    	}
    	return ret;
    }
    int main()
    {
    	n=gi();m=gi();k=gi();
    	c[0][0]=1;
    	for(int i=1;i<=200;i++)
    	{
    		c[i][0]=1;
    		for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod;
    	}
    	S[0][0]=1;
    	for(int i=1;i<=200;i++)
    	{
    		for(int j=1;j<=200;j++)
    			S[i][j]=(S[i-1][j-1]+1ll*j*S[i-1][j]%Mod)%Mod;
    	}
    	for(int i=1;i<=m;i++)u[i]=gi();
    	for(int i=1;i<=m;i++)r[i]=gi();
    	int ans=0;
    	for(int i=0,f=(n-k-1)&1?Mod-1:1;i<=n-k-1;i++,f=Mod-f)
    	{
    		int res=1ll*f*c[n-k-1][i]%Mod;
    		for(int j=1;j<=m;j++)res=1ll*res*c[i][r[j]-1]%Mod;
    		ans=(ans+res)%Mod;
    	}
    	ans=1ll*ans*c[n-1][k]%Mod;
    	for(int i=1;i<=m;i++)
    	{
    		int res=0;
    		for(int p=0,f=(r[i]-1)&1?Mod-1:1;p<r[i];p++,f=Mod-f)
    			res=(res+1ll*f*c[r[i]-1][p]%Mod*qpow(u[i],p)%Mod*calc(u[i],n-p-1)%Mod)%Mod;
    		ans=1ll*ans*res%Mod;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    DbUtils类的添加,修改,删除
    QueryRunner类的八种结果处理集
    中国传统文化---------斗地主----------
    剑指Offer42 左旋字符串
    剑指Offer41 反转单词顺序,单词字符顺序不变
    剑指Offer40 和为s的连续正数序列
    剑指Offer39 数组中寻找和为sum的两个数字
    剑指Offer36 数字在排序数组中出现的次数
    剑指Offer37 二叉树深度与平衡二叉树判断
    剑指Offer38 数组所有数字出现两次,只有两个出现了一次,找出这两个数字
  • 原文地址:https://www.cnblogs.com/fexuile/p/12868858.html
Copyright © 2020-2023  润新知