[NOIP2011 提高组] 计算系数

题目描述

给定一个多项式 (by+ax)^k(by+ax)k,请求出多项式展开后 x^n\times y^mxn×ym 项的系数。

输入格式

输入共一行,包含 55 个整数,分别为 a,b,k,n,ma,b,k,n,m,每两个整数之间用一个空格隔开。

输出格式

输出共一行,包含一个整数,表示所求的系数。

这个系数可能很大,输出对 1000710007 取模后的结果。

输入输出样例

输入 #1复制

1 1 3 1 2

输出 #1复制

3

说明/提示

【数据范围】

对于 30\%30% 的数据,有 0\le k\le 100≤k≤10。

对于 50\%50% 的数据,有 a=1a=1,b=1b=1。

对于 100\%100% 的数据,有 0\le k\le 10000≤k≤1000,0\le n,m\le k0≤n,m≤k,n+m=kn+m=k,0\le a,b\le 10^60≤a,b≤106。

noip2011 提高组 day2 第 1 题。

1.

——这一道题目,看别人都是用杨辉三角做的,可偏偏我这个菜鸟不会。于是就打了个类似于dp的做法。

——f[i][j]表示x^iy^j的系数,(默认k=i+j),可以得到转移:f[i][j]=f[i-1][j]*a+f[i][j-1]*b;

——于是大致的思路就好啦,然后是细节,如f[0][0]是1,这类的要注意

代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int a,b,k,n,m;
    long long f[1005][1005];
    int main()
    {
        scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
        f[0][0]=1;
        for (int i=0;i<=n;i++)
            for (int j=0;j<=m;j++)
            {
                if (i==0 && j==0) continue;
                f[i][j]=0;
                if (i>0)
                    f[i][j]=(f[i][j]+f[i-1][j]*a)%10007;
                if (j>0)
                    f[i][j]=(f[i][j]+f[i][j-1]*b)%10007;
            }
        printf("%lld\n",f[n][m]);
        return 0;
    }

 

2.

Solution

根据二项式定理,

(a+b)^n=\sum_{k=0}^nC_{n}^{k}a^kb^{n-k}(a+b)n=k=0∑n​Cnk​akbn−k

那么

(ax+by)^k=\sum_{p=0}^kC_{k}^p(ax)^p(by)^{k-p}=\sum_{p=0}^k(C_{k}^pa^pb^{k-p})x^py^{k-p}(ax+by)k=p=0∑k​Ckp​(ax)p(by)k−p=p=0∑k​(Ckp​apbk−p)xpyk−p

算a^n,b^man,bm需要用快速幂.

  • 可以根据组合式的递推公式算组合数.我是这么写的.

C_n^m=C_{n-1}^m+C_{n-1}^{m-1}Cnm​=Cn−1m​+Cn−1m−1​

  • 或者是利用组合数的定义式,但是因为有取余, 所以要用逆元.

C_n^m=\frac{n!\mod 10007}{m!(n-m)!\mod 10007}=n!\times [m!(n-m)!]^{-1}\mod 10007Cnm​=m!(n−m)!mod10007n!mod10007​=n!×[m!(n−m)!]−1mod10007

其中[m!(n-m)!]^{-1}[m!(n−m)!]−1为逆元, 这个可以直接用费马小定理, 正好前面写了快速幂, 岂不是美滋滋.

Code

#include<cstdio>
#define N 1005
#define mod 10007
using namespace std;

#define int long long
int c[N][N];
int a,b,k,n,m;
int pow(int x,int y){
    int ans=1,pas=x;
    while(y){
        if(y&1)ans*=pas%mod,ans%=mod;
        pas=(pas*pas)%mod;
        y>>=1;
    }
    return ans%mod;
}

int dfs(int n,int m){
    if(!m)return c[n][m]=true;if(m==1)return c[n][m]=n;
    if(c[n][m])return c[n][m];
    if(n-m<m)m=n-m;
    return c[n][m]=(dfs(n-1,m)+dfs(n-1,m-1))%mod;
}

main(){
    //freopen("factor.in","r",stdin);
    //freopen("factor.out","w",stdout);
    scanf("%lld%lld%lld%lld%lld",&a,&b,&k,&n,&m);
    c[1][0]=c[1][1]=1;a%=mod;b%=mod;
    int ans=1;
    ans*=(pow(a,n)*pow(b,m))%mod;
    if(n>m)n=m;
    ans*=dfs(k,n)%mod;ans%=mod;
    /*for(int i=1;i<=k;++i){
        for(int j=0;j<=i;++j)
            printf("%d ",c[i][j]);
        printf("\n");
    }*/
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值