您的位置:首页 > 其它

SGU 108 Self-numbers 2(数论)

2016-04-14 10:34 405 查看
Description

定义d(n)为n加上n的各位数字之和,例如d(75)=75+7+5=87

n叫d(n)的生成元,如果一个数没有生成元则称这个数为自私数,现给出一整数n,问1~n中自私数的个数,然后给出k个数a[i],输出1~k中第a[i]个自私数

Input

第一行两个整数n和k,第二行k个整数a[i]表示要输出1~n中第a[i]个自私数(1<=n<=10^7,1<=k<=5000)

Output

输出第一行为1~n中自私数的个数,第二行k个数表示第a[i]个自私数

Sample Input

100 10

1 2 3 4 5 6 7 11 12 13

Sample Output

13

1 3 5 7 9 20 31 75 86 97

Solution

内存太小开10^7数组就MLE,考虑数据范围(<=10^7)可知d(n)<=n+64,所以开一个64的标记数组循环使用,首先对所有查询排序,如果一个数没有被标记则自私数数量加一,如果当前自私数的数量恰为某些查询则将这个记录到答案数组中,之后其生成的数标记表示其不是自私数,之后再将查询按输入编号排序输出即可

Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 5555
int n,k,vis[maxn];
struct node
{
int pos,id,ans;
}q[maxn];
int cmp1(node a,node b)
{
return a.pos<b.pos;
}
int cmp2(node a,node b)
{
return a.id<b.id;
}
int count(int x)
{
int ans=0;
while(x)
ans+=x%10,x/=10;
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
int res=0,cnt=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<k;i++)scanf("%d",&q[i].pos),q[i].id=i;
sort(q,q+k,cmp1);
for(int i=1;i<=n;i++)
{
if(!vis[i%64])
{
cnt++;
while(res<k&&cnt==q[res].pos)q[res++].ans=i;
}
vis[(i+count(i))%64]=1;
vis[i%64]=0;
}
sort(q,q+k,cmp2);
printf("%d\n",cnt);
for(int i=0;i<k;i++)
printf("%d%c",q[i].ans,i==k-1?'\n':' ');
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: