SGU 108 Selfnumbers 2

SGU_108

    这个题目可以直接筛出来结果,但要注意几个问题:①数组不够大,但由于推断的时候前后影响的区间并不大,因此我们可以把数组循环使用,对数组操作的时候多加一个取模运算即可。②空间不允许我们先把所有结果都处理出来,因此我们可以在筛的过程中,标记一下当前筛出的是第几个数,如果是需要输出的,再存到指定位置去即可,这样只要开出K的空间来就可以了。③由于si可能是无序的,而我们在筛的过程中只能顺序找到,而我们又不能每次都花O(K)的时间去看看当前是不是要输出的,所以需要预先按si的值排下序,为了能够方便查找、更改,我们不能直接对si排序,但可以对si的标号按si的大小进行排序,同时还要注意si有可能有相同大小的值。

    此外,取模运算的时候如果用位运算代替的话,会让效率高很多。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXD 100010
#define MAXK 5010
const int D = (1 << 16) - 1;
int N, K, a[MAXK], r[MAXK];
char d[MAXD];
int cmp(const void *_p, const void *_q)
{
int *p = (int *)_p;
int *q = (int *)_q;
return a[*p] - a[*q];
}
int get(int n)
{
int res = n;
while(n)
{
res += n % 10;
n /= 10;
}
return res;
}
void solve()
{
int i, j, k, num, t;
for(i = 0; i < K; i ++)
scanf("%d", &a[i]);
a[K] = 0;
for(i = 0; i < K; i ++)
r[i] = i;
qsort(r, K, sizeof(r[0]), cmp);
r[K] = K;
memset(d, '\0', sizeof(d));
num = k = 0;
for(i = 1; i <= N; i ++)
{
if(!d[i & D])
{
++ num;
while(num == a[r[k]])
a[r[k ++]] = i;
}
t = get(i);
if(t <= N)
d[t & D] = '0';
d[i & D] = '\0';
}
printf("%d\n", num);
printf("%d", a[0]);
for(i = 1; i < K; i ++)
printf(" %d", a[i]);
printf("\n");
}
int main()
{
while(scanf("%d%d", &N, &K) == 2)
{
solve();
}
return 0;
}


原文地址:https://www.cnblogs.com/staginner/p/2300689.html