2017 11 6模拟赛T1

作为一个毒瘤出题人(wzy:我不是毒瘤出题人,这些题明明很水的),wzy的题干十分复杂,但是把题意简化之后,相当简单粗暴。。。

求首项为1,等比为m,项数为t的等比数列的和,答案对k取模

不保证m与k互质

如果m与k互质的话,用等比数列的求和公式在求个逆元就能解决了,但是本题显然不能,于是必须考虑不含有除法的算法

于是就有了分治求等比数列和的办法。

设s(x)为等比数列的第n项

由等比数列的性质得到s(y)=s(x)*m^(y-x) (y>x)

将一个长度为2r的等比数列拆分成登场的两部分,对应的项的比均为m^r,所以两部分和的差值也为m^r,所以只需要计算出前r项的和,就可以直接得到后r项的和。

如果数列的长度为2r+1,那么必须手动计算出第2r+1项的值,然后将后面的2r项拆分计算。

对于整个数列,递归计算,便可以在logt的时间内求出解。

 

#include<cstdio>
void read(int &y)
{
    y=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9')
    {
        y=y*10+x-'0';
        x=getchar();
    }
}
int m,t,k;
long long ksm(long long a,long long b)
{
    long long s=a,re=1;
    while(b)
    {
        if(b&1) re=re*s%k;
        s=s*s%k;
        b>>=1;
    }
    return re%k;
}
long long sum(int l,int r)
{
    if(l==r) return 1; 
    if((r-l+1)&1) return (ksm(m,r)+sum(l,(r-1)>>1)*(ksm(m,((r-1)>>1)+1)+1))%k;
    else return (sum(l,r>>1)*(ksm(m,(r>>1)+1)+1))%k;
}
int main()
{
    read(m);read(t);read(k);
    printf("%d",sum(0,t-1));
    return 0;
}

 

posted @ 2017-11-06 17:09  Excim  阅读(121)  评论(0编辑  收藏  举报