poj 1845 Sumdiv

题目:http://162.105.81.212:8080/problem?id=1845

大意:求A^B的所有因子的和。

思考:在纸上画一画就知道了,可以枚举A^B的第n个素因子的次方取值分别求和,由只含前n-1个素因子的因子和推出前n个,以此分治(或叫递推)。

      具体做法:对A分解因式(类似欧拉函数的求法),对每个素因子p,假如是e次方,扩大b倍,然后求1+p1+p2+...+pe这个等比数列的和,其中要用到等比数列求和公式,要除以p-1这个东西,当p-1与9901互素的时候还好,但万一不互素呢?

      这种情况我不会,后来才知道,其实只要把mod,即9901,乘上个p-1 以后就可以随便除以p-1了(形象地想,不一定对:也就是把整个数域扩大了p-1倍,这样p-1就成了一个单位,相当于原来的单位1,这时除以p-1也就相当于除以单位1而已……),于是问题就解决了。

      可能这是数论书上的结论吧,数论概论买来还没看- -,到时候看到了再在这里补上那条结论吧(好像其实就是当d|MOD的时候,同余模运算里面可以随便除以d,当然d与MOD互素的时候直接用extgcd求逆元再乘就可以了……)。

      另外注意数据范围,由于MOD乘上了一个数,中间运算可能会超int,尤其注意乘法的时候,还可能超long long!!!只能拆成二进制来边模边加着乘了至。看来像Mul(),Pow()这种函数,在数论题里面应该是必写的了,谁知道他什么时候会超范围。


标程:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
const ll M = 9901;

ll Mul(ll a,ll b,ll p) {
    a%=p;
    ll res=0;
    while(b) {
        if(b&1) {
            res+=a;
            if(res>p) res-=p;
        }
        a*=2,b/=2;
        if(a>p) a-=p;
    }
    return res;
}

ll Pow(ll a,ll b,ll p) {
    if(b==0) return 1;
    ll t=Pow(a,b/2,p);
    t=Mul(t,t,p);
    if(b&1) t=Mul(t,a,p);
    return t;
}

int main()
{
    ll a,b;
    while(~scanf("%lld%lld",&a,&b)) {
//        if(b==0) {
//            puts("1");
//            continue;
//        }
//        if(a==0) {
//            puts("0");
//            continue;
//        }
        ll ans=1;
        for(ll i=2;i*i<=a;i++) if(a%i==0) {
            ll e=0;
            while(a%i==0) {
                e++;
                a/=i;
            }
            e*=b;
            ans=Mul(ans,(Pow(i,e+1,(i-1)*M)-1)/(i-1),M);
        }
        if(a>1) {
            ll e=b;
            ans=Mul(ans,(Pow(a,e+1,(a-1)*M)-1)/(a-1),M);
        }
        printf("%lld\n",ans);
    }

    return 0;
}

 

PS:不要怀疑。。上面那个网址就是POJ。。我无意中发现的。。不知为何,用联通宽带上这个比上poj.org快多了了,嘿嘿。。=。=。。。

posted @ 2012-06-16 00:54  lxc902  阅读(244)  评论(0编辑  收藏  举报