3291. 素数个数排序

10175102262 LarsPendragon

在实训的时候这道题有一个小技巧:先在本地算出1w以内的质数,然后直接无脑查询即可。
计算质数的程序:

#include <stdio.h>
#include <math.h>
int isPrime(int n)
{
    int i, max=sqrt(n);
    if(n%2==0)
        return 0;
    for(i=3; i<=max; i+=2)
        if(n%i==0)
            return 0;
    return 1;
}
int main()
{
    int i, cnt=0;
    for(i=3; i<10001; i++) if(isPrime(i)) {printf("%d,",i); cnt++;}//输出质数加逗号(除2以外)
    printf("\n%d",cnt);//输出质数个数
    return 0;
}

提交的程序:

#include <stdio.h>
#include <stdlib.h>
typedef struct{int s, e, cnt;}Number;
int cmp(const void*a, const void*b)
{
    Number *p1=(Number*)a, *p2=(Number*)b;
    if(p1->cnt==p2->cnt)
    {
        if(p1->s==p2->s) return p1->e-p2->e;
        return p1->s-p2->s;
    }
    return p1->cnt-p2->cnt;
}
int main(void)
{
    int T, I;
    scanf("%d",&T);
    for(I=0; I<T; I++)
    {
        int n, i, j, k, prime[1229]={/*这里是质数表*/};
        Number num[10000];
        scanf("%d",&n);
        for(i=0; i<n; i++) scanf("%d %d",&num[i].s,&num[i].e);
        for(i=0; i<n; i++)
        {
            num[i].cnt=0;
            int start=num[i].s, end=num[i].e;
            for(k=0; k<1229; k++) if(prime[k]>=start) break;
            for(j=start; j<=end; j++)
                if(j==prime[k]) {k++; num[i].cnt++;}
        }
        qsort(num, n, sizeof(num[0]), cmp);
        printf("case #%d:\n",I);
        for(i=0; i<n; i++) printf("%d %d %d\n",num[i].s,num[i].e,num[i].cnt);
    }
    return 0;
}
10175102262 LarsPendragon

缺点就是太暴力了……

Garin1029

绝杀

10160350104

666

yu_guanglu

把时间优化到了0.05秒,惊讶的发现只有两个测试用例。
说下优化方向:
1.使用线性时间生成10000以内素数表。楼上的讨论大部分没有这样做。一开始认为从2到10000都是素数,从最小的素数开始,他的整倍数不是素数。整个过程大致类似于嘉宾灭灯,以(2),4,6,8,…,9998,10000,(3),6,9,…,9999,(5),10,…的遍历顺序以次标记合数。细节:使用累加器,代替乘法运算,万一编译器不给优化,我们就又快了一点。
2.使用线性时间计算从0到n的素数个数。这是一个简单的动态规划。设F(n)为[0,n]中的素数个数,那么有F(1)=0,如果n是合数F(n)=F(n-1),如果n是素数那么就加一。
3.读入数据的时候顺手把素数个数算出来,放在结构体里。
4.快速排序。这一部分我没有做优化,事实上如果按大于等于小于三类情况分组,应该会提速不少。(相信以后会有更快的代码出现的)
5.格式化输出

这个过程里T的增加只增加了从第三步开始的消耗,测试用例中的T越大,对我们越有利。

10165101292

md?

#include<stdio.h>
#include<math.h>
#include<stdlib.h>

#define MAXN 10000

// 第i个表示i是否为素数
bool map[MAXN];
//快查表第i个表示从0到i有多少素数
int table[MAXN];
//读入数组 用来排序输出
int arr[MAXN][2];

inline int cmp(const void* a, const void *b) {
    int *left = (int*)a;
    int *right = (int*)b;

    int val1 = table[*(left+1)] - table[*left - 1] - (table[*(right+1)] - table[*right - 1]);
    if (val1 != 0)
        return val1;
    else {
        int val2 = *left - *right;
        if (val2 != 0)
            return val2;
        else
            return *(left+1) - *(right+1);
    }
}

int main() {

    //判定是否为素数 true不是素数 false是素数
    map[0] = map[1] = map[4]=true;
    for (int i = 6; i < MAXN; i++) {
        //快速判断提高速度
        if (i % 2 == 0 || i % 3 == 0 || i % 5 == 0 ) {
            map[i] = true;
            continue;
        }
        //否则判断
        int middle = sqrt(i);
        for (int j = 3; j <= middle; j++) {
            if (i%j == 0) {
                map[i] = true;
                break;
            }
        }
    }

    //生成表第i个表示从0到i有多少素数
    for (int i = 1; i < MAXN; i++) {
        if (!map[i])
            table[i] = table[i - 1] + 1;
        else
            table[i] = table[i - 1];
    }

    //读入快排一下
    int times = 0;
    scanf("%d", &times);
    for (int s = 0; s < times; s++) {
        int num = 0;
        scanf("%d",&num);
        for (int i = 0; i < num; i++) {
            scanf("%d %d", &arr[i][0], &arr[i][1]);
        }

        qsort(arr, num, sizeof(int) * 2, cmp);

        printf("case #%d:\n", s);
        for (int i = 0; i < num; i++) {
            printf("%d %d\n", arr[i][0], arr[i][1]);
        }
    }

    return 0;
}
10165101292

两年没玩了 今天帮室友写 怎么也优化不好 思路和上面是一样的 不过代码更好理解(代码写那么挤不好)
60MS左右 看机子速度 最快44ms

include

include

include

define MAXN 10000

//图 (第i个表示i是否为素数)
bool map[MAXN];
//快查表(第i个表示从0到i有多少素数)
int table[MAXN];
//读入数组 用来排序输出
int arr[MAXN][2];

//inline实测无用
inline int cmp(const void a, const void b) {
int left = (int)a;
int right = (int)b;

int val1 = table[*(left+1)] - table[*left - 1] - (table[*(right+1)] - table[*right - 1]);
if (val1 != 0)
    return val1;
else {
    int val2 = *left - *right;
    if (val2 != 0)
        return val2;
    else
        return *(left+1) - *(right+1);
}

}

int main() {

//判定是否为素数 true不是素数 false是素数 
map[0] = map[1] = map[4]=true;
for (int i = 6; i < MAXN; i++) {
    //快速判断提高速度
    if (i % 2 == 0 || i % 3 == 0 || i % 5 == 0 ) {
        map[i] = true;
        continue;
    }
    //否则麻烦的判断
    int middle = sqrt(i);
    for (int j = 3; j <= middle; j++) {
        if (i%j == 0) {
            map[i] = true;
            break;
        }
    }
}

//生成表第i个表示从0到i有多少素数
for (int i = 1; i < MAXN; i++) {
    if (!map[i])
        table[i] = table[i - 1] + 1;
    else
        table[i] = table[i - 1];
}

//读入快排一下
int times = 0;
scanf("%d", &times);
for (int s = 0; s < times; s++) {
    int num = 0;
    scanf("%d",&num);
    for (int i = 0; i < num; i++) {
        scanf("%d %d", &arr[i][0], &arr[i][1]);
    }

    qsort(arr, num, sizeof(int) * 2, cmp);

    printf("case #%d:\n", s);
    for (int i = 0; i < num; i++) {
        printf("%d %d\n", arr[i][0], arr[i][1]);
    }
}

return 0;

}

Fifnmar

@yu_guanglu 的发言中有一个错误。他说的筛出素数的埃氏筛方法(步骤 1)不是线性的,应该用欧拉筛。

我用他说的埃氏筛写了一下代码。

int main() {
    using namespace std;
    constexpr size_t PRIME_UBOUND = 10001;
    vector<bool> is_prime(PRIME_UBOUND, true);
    vector<uint32_t> prime_cnt(PRIME_UBOUND, 0);
    for (uint32_t i = 2; i < PRIME_UBOUND; ++i) {
        prime_cnt[i] = is_prime[i] + prime_cnt[i - 1];
        if (is_prime[i]) {
            for (uint32_t j = i << 1; j < PRIME_UBOUND; j += i) {
                is_prime[j] = false;
            }
        }
    }
    uint32_t t; cin >> t;
    for (uint32_t query = 0; query < t; ++query) {
        printf("case #%u:\n", query);
        uint32_t n; cin >> n;
        struct PrimeRange {
            uint32_t start, last, val;
            bool operator<(PrimeRange const& rhs) const {
                if (val == rhs.val) {
                    if (start == rhs.start) {
                        return last < rhs.last;
                    } else {
                        return start < rhs.start;
                    }
                } else {
                    return val < rhs.val;
                }
            }
        };
        vector<PrimeRange> ranges(n);
        for (auto& r : ranges) {
            cin >> r.start >> r.last;
            r.val = prime_cnt[r.last] - prime_cnt[r.start - 1];
        }
        sort(ranges.begin(), ranges.end());
        for (auto const& r : ranges) {
            printf("%u %u\n", r.start, r.last);
        }
    }
}
Fifnmar

C 语言写一下吧,我之前写的代码比较烂(虽然这个也不一定好 hhh)

#include <stdio.h>
#include <stdlib.h>

void pre_calculate_primes();
void solve();

int main() {
    // pre-calculate the primes.
    pre_calculate_primes();

    int t;
    scanf("%d", &t);
    for (int i = 0; i != t; ++i) {
        printf("case #%d:\n", i);
        solve();
    }
}

#define MAX 10000
int primes[MAX]; // primes[i] == number of primes up to i, inclusive.

/** Calculates the number of primes from 0 to i for all i in 0..MAX. */
void pre_calculate_primes() {
    // First, we use `primes` to mean `is_prime`. if primes[i] == 1, then it means i is a prime. We shall fix this in
    // the last part.
    primes[0] = primes[1] = 0;

    // presume that all of them are primes, and exclude them as we go. See Eratosthenes's Sieve.
    for (int i = 2; i != MAX; ++i) {
        primes[i] = 1;
    }

    for (int i = 2; i != MAX; ++i) {
        if (!primes[i]) { continue; }
        for (int j = i * 2; j < MAX; j += i) {
            primes[j] = 0; // they are not primes.
        }
    }

    // Now we fix the problem. We will accumulate all numbers from 0 to MAX so the array `primes` records the number
    // of primes up to each number, instead of whether that number is a prime.
    for (int i = 1; i != MAX; ++i) {
        primes[i] += primes[i - 1];
    }
}

struct PrimeRange {
    int start, end, cnt;
};

int cmp_range(struct PrimeRange const* lhs, struct PrimeRange const* rhs) {
    if (lhs->cnt != rhs->cnt) {
        return lhs->cnt - rhs->cnt;
    }
    if (lhs->start != rhs->start) {
        return lhs->start - rhs->start;
    }
    return lhs->end - rhs->end;
}

struct PrimeRange ranges[MAX];

void solve() {
    int n;
    scanf("%d", &n);

    for (int i = 0; i != n; ++i) {
        scanf("%d%d", &ranges[i].start, &ranges[i].end);
        ranges[i].cnt = primes[ranges[i].end] - primes[ranges[i].start - 1];
    }

    qsort(ranges, n, sizeof *ranges, cmp_range);

    for (int i = 0; i != n; ++i) {
        printf("%d %d\n", ranges[i].start, ranges[i].end);
    }
}
你当前正在回复 博客/题目
存在问题!