• [CSP-S模拟测试]:礼物(数学)


    题目传送门(内部题80)


    输入格式

      第一行输入一个正整数$n$。
      第二行到第$n+1$行每行两个正整数$a_i$和$b_i$表示第$i$个礼物中包含$a_i$个红宝石和$b_i$个绿宝石。


    输出格式

      输出一个整数表示方案数。


    样例

    见下发文件


    数据范围与提示

      对于$20\%$的数据:$nleqslant 5,000,a_i,b_ileqslant 1,000,000$
      对于另外$30\%$的数据:$a_i,b_ileqslant 4,000$
      对于另外$20\%$的数据:$nleqslant 50,000,sum a_i+sum b_ileqslant 2,000,000$
      对于$100\%$的数据:$nleqslant 100,000,sum a_i+sum b_ileqslant 20,000,000$


    题解

    转化一下题意,就是求$sum limits_{i!=j}C_{a_i+b_i+a_j+b_j}^{a_i+a_j}$。

    $$C_{a_i+b_i+a_j+b_j}^{a_i+a_j}=sum limits_{t=0}^{a_i+a_j}C_{a_i+b_i}^{t} imes C_{a_j+b_j}^{a_i+a_j-t}=sum limits_{t=-a_i}^{a_j}C_{a_i+b_i}^{t+a_i} imes C_{a_j+b_j}^{a_j-t}$$

    考虑$t$的枚举范围。当$b_ileqslant t$时,$C_{a_i+b_i}^{t+a_i}$恒为$0$;当$a_jleqslant t$时,$C_{a_j+b_j}^{a_j-t}$恒为$0$。所以式子等价于$sum limits_{t=-a_i}^{b_i}C_{a_i+b_i}^{t+a_i} imes C_{a_j+b_j}^{a_j-t}$

    考虑对于每个$t$,维护出$C_{a_j+b_j}^{a_j-t}$的和,每次新加入一个数,暴力枚举$t$,贡献答案。

    时间复杂度:$Theta(sum a_i+sum b_i+n)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=1000000007;
    const int base=20000000;
    int n;
    int a[100001],b[100001];
    long long jc[20000001],inv[20000001],sum[40000001],ans;
    long long qpow(long long x,long long y)
    {
    	long long res=1;
    	while(y)
    	{
    		if(y&1)res=res*x%mod;
    		x=x*x%mod;
    		y>>=1;
    	}
    	return res;
    }
    void pre_work()
    {
    	jc[0]=1;
    	for(int i=1;i<=20000000;i++)jc[i]=jc[i-1]*i%mod;
    	inv[20000000]=qpow(jc[20000000],mod-2);
    	for(int i=20000000;i;i--)
    		inv[i-1]=inv[i]*i%mod;
    }
    long long C(long long x,long long y)
    {
    	if(!y)return 1;
    	return jc[x]*inv[y]%mod*inv[x-y]%mod;
    }
    int main()
    {
    	pre_work();
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
    	for(int i=1;i<=n;i++)
    		for(int j=min(-a[i],-b[i]);j<=max(a[i],b[i]);j++)
    		{
    			if(a[i]+j>=0)ans=(ans+1LL*C(a[i]+b[i],a[i]+j)*sum[j+base]%mod)%mod;
    			if(a[i]-j>=0)sum[j+base]=(sum[j+base]+C(a[i]+b[i],a[i]-j))%mod;
    		}
    	printf("%lld",(ans<<1)%mod);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Android四大基本组件介绍与生命周期
    论Android产品高效开发之路
    android工程目录分析
    android推送思路
    android类库
    Android实现应用下载并自动安装apk包
    自定义 Android 对话框 (AlertDialog) 的样式
    Android adb shell 命令详解
    Complexities
    Combination Sum II
  • 原文地址:https://www.cnblogs.com/wzc521/p/11722341.html
Copyright © 2020-2023  润新知