UVAlive 6153 LCM Pair Sum 解题报告

题目

题意:

对于一个数n,有一些这样的一个数对(p,q),满足1<=p<=q<=n,且lcm(p,q)=n。则f(n)等于所有的这样的数对的p和q的和。已知n(以底数和指数的形式给出),求f(n)。

题解:

考虑底数pi,对应指数ai,若p的指数小于ai,则q的指数必等于ai;若p的指数等于ai,则q的指数无所谓。通过枚举p每个底数的指数,可知q有多少种取法(可能会导致p>q,没关系)。加起来就可以。

但是直接枚举p的每一个取值会TLE。显然p的指数小于ai时q的方案数是相同的,所以可以一起算。

到最后除了(n,n)只算了一次外,每个数对都算了两次,所以加上2*n后再除2就是答案。

有些数据不预处理出乎意料地慢,要注意。


//Time:316ms
//Memory:0KB
//Length:1362B
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define MAXN 1010
#define MOD 1000000007

int p[MAXN],a[MAXN],c,mnum[MAXN],db[MAXN][2];
long long ans;
int pow_mod(long long a,int po)
{
    long long ret=1;
    while(po)
    {
        if(po&1)    ret=ret*a%MOD;
        po>>=1,a=a*a%MOD;
    }
    return ret;
}
inline int caldb(int a,int b)
{
    return (long long)(pow_mod(a,b)-1)*pow_mod(a-1,MOD-2)%MOD;
}
void dfs(int h,long long now,long long now2,long long fan1,long long fan2)
{
    for(int i=h;i<c;++i)
    {
        dfs(i+1,now*db[i][0]%MOD,now2*mnum[i]%MOD,fan1,fan2*a[i]%MOD);
        now=now*mnum[i]%MOD,now2=now2*db[i][1]%MOD,fan1=fan1*(1+a[i])%MOD;
    }
    ans=(ans+now*fan1%MOD+now2*fan2%MOD)%MOD;
}
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    int ncase,two=pow_mod(2,MOD-2);
    scanf("%d",&ncase);
    for(int hh=1;hh<=ncase;++hh)
    {
        scanf("%d",&c);
        ans=0;
        for(int i=0;i<c;++i)
        {
            scanf("%d%d",&p[i],&a[i]);
            mnum[i]=pow_mod(p[i],a[i]);
            db[i][0]=caldb(p[i],a[i]);
            db[i][1]=caldb(p[i],a[i]+1);
        }

        dfs(0,1,1,1,1);
        long long tmp=1;
        for(int i=0;i<c;++i)    tmp=tmp*mnum[i]%MOD;
        ans=(ans+tmp*2%MOD)*two%MOD;
        printf("Case %d: %d\n",hh,(int)ans);
    }
    return 0;
}


你可能感兴趣的:(UVAlive 6153 LCM Pair Sum 解题报告)