【埃式筛法】My pretty girl Noora CodeForces - 822D

本文介绍了一道涉及埃式筛法与递推的复杂算法题,该题要求计算特定数学序列的和,并在解答过程中分享了从超时到正确解答的心得体会,包括快速幂的应用与取模操作的重要性。

Think:
1知识点:埃式筛法+递推
2题意:n个女生参加选美大赛,每次分成n/x组,每组进行x*(x-1)/2次比较,然后晋级n/x名女生,不断分组,不断选拔,最终只留下1名女生作为冠军,f[n]表示n名女生决出冠军的最少比较次数(通过改变x可影响f[x]).
输入t, l , r (1 ≤ t < 1e9 + 7, 2 ≤ l ≤ r ≤ 5·1e6)
求解:t^0·f(l) + t^1·f(l + 1) + … + t^(r - l)·f(r)

3借鉴前辈解题思路:
这里写图片描述
4反思:
1>方法要立足理解题意,一开始未认真分析就使用快速幂进而超时
2>t^()未注意及时取模,导致Wrong Answer

vjudge题目链接

建议参考博客1
建议参考博客2

以下为Time Limit Exceeded代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int mod = 1000000007;
const int N = 5001400;

int prim[N], tp, link[N];
LL f[N];

void get_primes();
void get_f();
LL find_primes(LL x);
LL power(LL x, int k, int mod);

int main(){
    get_primes();
    get_f();
    LL x, sum;
    int l, r, k, i;
    while(~scanf("%lld %d %d", &x, &l, &r)){
        sum = 0;
        for(k = 0, i = l; i <= r; i++, k++){
            sum = (sum + power(x, k, mod)*f[i]) % mod;
        }
        printf("%lld\n", sum);
    }
    return 0;
}
void get_primes(){
    tp = 0;
    memset(prim, 0, sizeof(prim));
    prim[1] = 1, prim[2] = 0;
    for(LL i = 2; i < N; i++){
        if(!prim[i]){
            link[tp++] = i;
            for(LL j = i*i; j < N; j += i){
                prim[j] = 1;
            }
        }
    }
}
void get_f(){
    for(LL i = 2; i < N; i++){
        if(!prim[i])
            f[i] = i*(i-1)/2;
        else {
            LL t = find_primes(i);
            f[i] = (i/t)*f[t] + f[i/t];
        }
        f[i] %= mod;
    }
}
LL find_primes(LL x){
    LL ans;
    for(LL i = 0; i < tp; i++){
        if(x % link[i] == 0){
            ans = link[i];
            break;
        }
    }
    return ans;
}
LL power(LL x, int k, int mod){
    LL ans = 1;
    while(k){
        if(k & 1)
            ans = (ans*x) % mod;
        x = (x*x) % mod;
        k >>= 1;
    }
    return ans;
}

以下为Wrong Answer代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int mod = 1000000007;
const int N = 5001400;

int prim[N], tp, link[N];
LL f[N];

void get_primes();
void get_f();
LL find_primes(LL x);

int main(){
    get_primes();
    get_f();
    LL x, sum, po;
    int l, r, i;
    while(~scanf("%lld %d %d", &x, &l, &r)){
        sum = 0, po = 1;
        for(i = l; i <= r; i++){
            sum = (sum + po*f[i]) % mod;
            po *= x;
        }
        printf("%lld\n", sum);
    }
    return 0;
}
void get_primes(){
    tp = 0;
    memset(prim, 0, sizeof(prim));
    prim[1] = 1, prim[2] = 0;
    for(LL i = 2; i < N; i++){
        if(!prim[i]){
            link[tp++] = i;
            for(LL j = i*i; j < N; j += i){
                prim[j] = 1;
            }
        }
    }
}
void get_f(){
    for(LL i = 2; i < N; i++){
        if(!prim[i])
            f[i] = i*(i-1)/2;
        else {
            LL t = find_primes(i);
            f[i] = (i/t)*f[t] + f[i/t];
        }
        f[i] %= mod;
    }
}
LL find_primes(LL x){
    LL ans;
    for(LL i = 0; i < tp; i++){
        if(x % link[i] == 0){
            ans = link[i];
            break;
        }
    }
    return ans;
}

以下为Accepted代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int mod = 1000000007;
const int N = 5001400;

int prim[N], tp, link[N];
LL f[N];

void get_primes();
void get_f();
LL find_primes(LL x);

int main(){
    get_primes();
    get_f();
    LL x, sum, po;
    int l, r, i;
    while(~scanf("%lld %d %d", &x, &l, &r)){
        sum = 0, po = 1;
        for(i = l; i <= r; i++){
            sum = (sum + po*f[i]) % mod;
            po = (po*x) % mod;
        }
        printf("%lld\n", sum);
    }
    return 0;
}
void get_primes(){
    tp = 0;
    memset(prim, 0, sizeof(prim));
    prim[1] = 1, prim[2] = 0;
    for(LL i = 2; i < N; i++){
        if(!prim[i]){
            link[tp++] = i;
            for(LL j = i*i; j < N; j += i){
                prim[j] = 1;
            }
        }
    }
}
void get_f(){
    for(LL i = 2; i < N; i++){
        if(!prim[i])
            f[i] = i*(i-1)/2;
        else {
            LL t = find_primes(i);
            f[i] = (i/t)*f[t] + f[i/t];
        }
        f[i] %= mod;
    }
}
LL find_primes(LL x){
    LL ans;
    for(LL i = 0; i < tp; i++){
        if(x % link[i] == 0){
            ans = link[i];
            break;
        }
    }
    return ans;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值