跟素数筛法很像,主要是标记和识别(忽略)标记,直接两层for循环水过,也就171毫秒,不过要注意数组的大小,太大没必要,还占时间。
看某神的分类是“链表”。。。。。。开始就是看了分类定向思维用链表做,调BUG吐了口老血,然后实在不想调了,两层for就够了。。。。。。
但是如果数据量再大的话,for很容易超时,链表还是比较优化的算法,但是对于此数据量没必要。
#include <stdio.h> #include <string.h> #define N 33850 ///卡一卡大小,使用尽量少的空间,也减少扫描的区间 int a[33860]; int b[3010]; int main() { int i, j, cou, cc, c; memset(a, 0, sizeof(a)); ///初始化标记数组 cc = 0; for (i = 2; i <= N; i++) { if (!a[i]) { ///找到排头的 b[++cc] = i; ///记录lucky number cou = i; c = 0; for (j = i; j <= N; j++) { if (!a[j] && i != j) { ///注意第一次扫的时候不c++ c++; if (c == cou) { a[j] = 1; ///标记,说明被派去刷碗,以后扫描时忽略ta c = 0; ///注意重置计数器 } } } } } int n; while (~scanf("%d", &n) && n) { printf("%d\n", b[n]); } return 0; }
后来用链表提交的代码,跑了60多毫秒,内存耗得差不多快两倍,以前写链表习题的时候总是习惯性的把不用的节点free掉,但是想到OJ在申请的一瞬间已经达到最大内存空间了,再free就是给自己找事了。代码长度也没有差多少,还是觉得两层for比较好,其实也就是储存方式不一样,但是对数组比较好操作。
#include <stdio.h> #include <string.h> #include <stdlib.h> #define N 33850 struct node { int num; struct node *next; }; int sizen = sizeof(node); int b[3010]; int main() { #if 0 /// freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); #endif // 1 node *head = NULL, *tail = NULL, *p = NULL; int i; for (i = 2; i <= N; i++) { ///从2开始,创建链表 p = (node *)malloc(sizen); p->num = i; p->next = NULL; if (head == NULL) { head = p; tail = head; } else { tail->next = p; tail = tail->next; } } int cou = 0, cc = 0; node *pre = NULL; for (p = head; p != NULL; head = head->next, p = head) { b[++cc] = p->num; ///将第一个没有被派去刷碗的记录下来 cou = p->num; ///记录此人的编号,用于循环 while (1) { for (i = 1; i <= cou; i++) { pre = p; p = p->next; if (p == NULL) break; ///此处很重要,一个循环没跑完就到头了 } if (p == NULL) ///到头了跳出 break; else { pre->next = p->next; ///派去刷碗 free(p); p = pre; ///注意等于前一个 } } } int n; while (~scanf("%d", &n) && n) { printf("%d\n", b[n]); } return 0; }