jdoj 1402 特殊的数 代码及分析
这是jobdu的好题,网上的解说都是用位运算的,但是我现在对位运算还不太了解,所以我的代码是用对数组的压缩使用来实现对小数目个数的统计的,也因此对存储空间的利用是不够充分的。
原理解释:一个int是4个字节组成的。在这题里面,如果开10^6的数组,4*10^6B≈4MB,这还没加上运行程序命令所需要的内存。由此可见,这样开数组是必定MLE的。但是我们可以发现,对于这题而言,每个数中我们所需要的状态只有0,1,2三种,于是我就想到数组在内存中的存储方式,并模仿它建立起一个大小只有50000的int数组。10^6 / (log(2^31) / log(3))<50000,由于数的范围是1~10^6,所以令数(a-1)/50000得到的值作为行位置,(a-1)%50000得到的值作为列位置,由此,一个100w的数组就被压缩成一个20行5w列的数组了。我的代码优化了输出,限定了输入的数的范围,最后遍历检测输出个数为1的数。
这种方法并不高效,我最多只能把它优化到1104kb 1610ms的运行内存和运行时间。
下面是我的代码,供大家参考:
View Code
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<math.h>
5 #define MAX 50000 //决定数组大小
6 #define POW 3 //每个数的状态数量
7
8
9 unsigned int cnt[MAX];
10
11 unsigned int ten(int pow) //这里我要特别提醒的是,C里面的pow函数返回值强制变成int后,可能得到的不是我们所想要的那个数
12 {
13 unsigned int back;
14
15 back=1;
16 while(pow--)back*=POW;
17
18 return back;
19 }
20
21 int amount(int a) //返回数a的个数
22 {
23 return (cnt[(a-1)%MAX]/ten((a-1)/MAX))%POW;
24 }
25
26 int main()
27 {
28 int i, c;
29 int n, m;
30 int min, max, maxn, minn;
31
32 while(scanf("%d", &n)!=EOF)
33 {
34 memset(cnt, 0, sizeof(cnt));
35 max=maxn=c=0;min=minn=9999999;
36 while(n--)
37 {
38 scanf("%d", &m);
39 if(min>m)min=m;
40 if(max<m)max=m;
41 if(amount(m)!=2)cnt[(m-1)%MAX]+=ten((m-1)/MAX); //数的个数≥2就不用继续加了
42 }
43 for(i=min; i<=max; i++)
44 if(amount(i)==1)
45 {
46 if(!c)minn=i;
47 c++;
48 if(maxn<i)maxn=i;
49 }
50 if(c)printf("%d\n", c);
51 else {printf("0\n");continue;}
52 for(i=minn; c!=1; i++)
53 if(amount(i)==1){printf("%d ", i);c--;}
54 for(; i<=maxn; i++)
55 if(amount(i)==1)printf("%d\n", i);
56 }
57
58 return 0;
59
60 }
2 #include<stdlib.h>
3 #include<string.h>
4 #include<math.h>
5 #define MAX 50000 //决定数组大小
6 #define POW 3 //每个数的状态数量
7
8
9 unsigned int cnt[MAX];
10
11 unsigned int ten(int pow) //这里我要特别提醒的是,C里面的pow函数返回值强制变成int后,可能得到的不是我们所想要的那个数
12 {
13 unsigned int back;
14
15 back=1;
16 while(pow--)back*=POW;
17
18 return back;
19 }
20
21 int amount(int a) //返回数a的个数
22 {
23 return (cnt[(a-1)%MAX]/ten((a-1)/MAX))%POW;
24 }
25
26 int main()
27 {
28 int i, c;
29 int n, m;
30 int min, max, maxn, minn;
31
32 while(scanf("%d", &n)!=EOF)
33 {
34 memset(cnt, 0, sizeof(cnt));
35 max=maxn=c=0;min=minn=9999999;
36 while(n--)
37 {
38 scanf("%d", &m);
39 if(min>m)min=m;
40 if(max<m)max=m;
41 if(amount(m)!=2)cnt[(m-1)%MAX]+=ten((m-1)/MAX); //数的个数≥2就不用继续加了
42 }
43 for(i=min; i<=max; i++)
44 if(amount(i)==1)
45 {
46 if(!c)minn=i;
47 c++;
48 if(maxn<i)maxn=i;
49 }
50 if(c)printf("%d\n", c);
51 else {printf("0\n");continue;}
52 for(i=minn; c!=1; i++)
53 if(amount(i)==1){printf("%d ", i);c--;}
54 for(; i<=maxn; i++)
55 if(amount(i)==1)printf("%d\n", i);
56 }
57
58 return 0;
59
60 }
written by Lyon