Jul
01
SGU 108 解题手记
2007 解题报告 Popularity: 1%
这个题目前还没有好的办法,只能在筛法的基础上做优化。筛法是这样的:对于任意一个k,将d(k)标记一下,这样,1-n之间不带标记的,就是self-number。
标记并不需要O(n)的空间,可以采用循环使用数组的办法,因为d(k)-k<=9*7=63,所以数组开到64就够了。
为了再取得一些时间上的优势,可以把10000以下的数的各个数位上数字之和预处理出来,这样,计算k的各个数位上数字之和所需时间就下降到O(1)了。
注意题目中给出的s1...sk并不是从小到大的。
Submit 1: WA on 2。可能是由于数组超界造成的,加设一个哨兵。特殊点n=1的时候也错了。并不是特殊点错了,而是只判断了[1,n-1]之间的self-number。
Submit 2: WA on 5。s1...sk不一定是不重复的。
Submit 3: AC。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include <cstdio> #include <algorithm> using namespace std; struct selfnum { int id,idx,num; }; inline bool cmp_id(const selfnum &s1,const selfnum &s2) { return s1.id<s2.id; } inline bool cmp_idx(const selfnum &s1,const selfnum &s2) { return s1.idx<s2.idx; } int main() { int n,k,r(0),p(0),sumdig[10000]; selfnum s[5001]; bool self[64]; scanf("%d%d",&n,&k); for (int i(0);i<k;i++) { scanf("%d",&s[i].idx); s[i].id=i; } s[k+1].idx=0; sort(s,s+k,cmp_idx); fill(self,self+64,true); for (int i(0);i<10000;i++) sumdig[i]=i/1000+i/100%10+i/10%10+i%10; for (int i(1);i<=n;i++) { if (self[i&63]) { r++; while (r==s[p].idx) s[p++].num=i; } int di=i+sumdig[i/10000]+sumdig[i%10000]; self[i&63]=true; self[di&63]=false; } sort(s,s+k,cmp_id); printf("%d\n",r); for (int i(0);i<k;i++) printf("%d ",s[i].num); return 0; } |
- http://www.briefdream.com/sgu-108/
- Tags:self-number, SGU, 数学, 数组, 筛法
- (0)comments | leave a reply
- Trackback URI