HDU 5490 Simple Matrix (2015合肥站网络赛1007 数学题)

这个看了秦总博客学会的,附上地址
博客介绍得很详细。
我原来的思路,找到每一个ai,bi对(n,m)的贡献。
我们可以写出
c(n,m)=ni=1ai(n+m1im1)+mi=1bi(n+m1in1)
ai=a1+(i1)d
bi=b1qi1
等差数列很容易求出来,但是等比数列很难,比赛的时候一直考虑等比数列能不能像等差数列一项求出通项,事实上失败了,并不知道有没有什么高级的方法能搞出来。
事实上,等差数列求和,一共就n项,这个时候我们暴力累加都可以完成任务,于是我们主要工作放到了等比数列上面。如果我们对初等数学还敏感的话,我们会想到能不能构造出一个等比或者等差数列?(我现在的数学水平真是不忍直视)
那么我们先把所有ai变成0,单独看bi。
对于第0行
0 b1 b1q b1q2 b1q3 b1qm
我们研究第1行的第i个数:
c(1,i)=ik=1bk
我们可以推出:
c(1,i)=qc(1,i1)+b1
即:
c(1,i)=qc(1,i1)+c(0,1)
这个形式直接就化成了
c(1,i)+c(0,1)q1=q(c(1,i1)+c(0,1)q1)
这样我们就构造出了一个等比数列,我们需要做的事情就是把 c(1,0)=c(0,1)q1
我们只需要把 aic(0,1)q1 就可以了。
这样我们把第一行变成了一个等比数列,那么第二行也可以用同样的方法变成等比数列。以此类推,第n行也可以变成等比数列。
我们这是时候需要找到每行的 c(i,0) 的值。
我们写几项就会发现: c(i,0)=qi1(q1)ib1
那么我们要求的东西就会变成:
c(n,m)=ni=1(ai(n+m1im1)qi1(q1)ib1)+qn1q1nb1qm
这样,后面一项用快速幂即可完成,前面一项只需要累加就可以了,注意处理逆元。注意 (n+m1(i+1)m1)=(n+m1im1)nin+m1i ,其实,这个倒过来求比较好,因为 (m1m1)=1 是个定值,所以我们可以倒过来求,比较方便。
下面附上AC代码:

#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y)  for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define MAXN 10010
#define MOD 1000000007

using namespace std;

void ex_gcd(LL a,LL b,LL&d ,LL& x,LL& y){
    if(!b)  {d = a;x = 1;y = 0;}
    else{ex_gcd(b,a%b,d,y,x);y -= x*(a/b);}
}

LL inv(LL a,LL mod){
    LL d,x,y;
    ex_gcd(a,mod,d,x,y);
    return d == 1 ? (x+mod)%mod : -1;
}

LL quickpow(LL a,LL p){
    LL ans=1;
    while(p){
        if(p&1) ans = (ans*a)%MOD;
        a = (a*a)%MOD;
        p >>= 1;
    }
    return ans;
}

LL b1,q,a1,d;
int n,m;

LL A(){
    b1 %= MOD; q %= MOD; a1 %= MOD; d %= MOD;
    LL res1 = (a1+d*(n-1))%MOD;
    LL inv1 = inv(q-1,MOD);
    LL tem = (inv1*q)%MOD;
    LL res2 = (((quickpow(tem,n-1)*inv1)%MOD)*b1)%MOD;
    LL res3 = 1;
    LL ans = (res1+MOD-res2)%MOD;
    inv1 = inv(q,MOD);
    tem = (q-1)*inv1%MOD;
    FOR(i,1,n){
        res1 = (res1+MOD-d)%MOD;
        res2 = res2*tem%MOD;
        LL t = (LL)(m-1)+(LL)i;
        LL tt = inv((LL)i,MOD);
        res3 = (res3*t%MOD)*tt%MOD;
        ans += ((res1+MOD-res2)%MOD)*res3%MOD;
    }
    return ans;
}

LL B(){
    LL p = (LL)m+n-1;
    LL t1 = quickpow(q,p);
    LL t2 = quickpow(q-1,n);
    t2 = inv(t2,MOD);
    LL ans = (t1*t2%MOD)*b1%MOD;
    return ans;
}

int main()
{
    //freopen("test.in","r",stdin);
    int T,tCase = 0;
    scanf("%d",&T);
    while(T--){
        printf("Case #%d: ",++tCase);
        scanf("%I64d%I64d%I64d%I64d%d%d",&b1,&q,&a1,&d,&n,&m);
        LL t1 = A();
        LL t2 = B();
        LL ans = (t1+t2)%MOD;
        printf("%I64d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值