L2-029 特立独行的幸福 (25 分)
题目
题目链接(因为总是被认定抄袭所以不敢复制了)
思路
好久没练了,卡了一个晚自习。
开始的思路是预处理,深搜1~1e4的所有数字,后来发现自己没有仔细审题,特立独行是相对于一个给定区间的,比如19其实是依赖于133的,但是因为区间是10~40,所以才是特立独行的。由此这个方法被废弃,写的巨复杂还错了。
后来就想出了较简单的搜索方法,先将a到b区间内的每个数都预处理一遍他们的依赖幸福数,将这些数按照迭代次序串成链表,并注意同时维护pre和next两个数组。之后再从a到b遍历,找到没有前驱节点的数字进行再一次深搜,如果深搜到了环那么记为不幸福,深搜到了1就是幸福且是特立独行的。
素数的预处理不要忘记。
代码
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef pair<int, int> P;
const int N = 1e4 + 9;
bool vis[N];
int nxt[N];
bool pre[N];
bool isprime[N];
int cnt;
void p()
{
isprime[0] = isprime[1] = 1;
for(int i = 2; i < N; i++)
{
if(vis[i])
continue;
for(int j = i * 2; j < N; j += i)
{
isprime[j] = 1;
vis[j] = 1;
}
}
}
int calc(int x)
{
int ans = 0;
while(x)
{
int tmp = x % 10;
ans += tmp * tmp;
x /= 10;
}
return ans;
}
void happy(int u)
{
if(u == 1 || nxt[u])
return ;
int v = calc(u);
nxt[u] = v;
pre[v] = u;
happy(v);
}
void dfs(int u)
{
if(u == 1)
return ;
if(vis[u])
{
cnt = 0;
return;
}
cnt++;
vis[u] = 1;
dfs(nxt[u]);
}
queue<P> que;
int main()
{
p();
int a, b;
cin >> a >> b;
for(int i = a; i <= b; i++)
happy(i);
for(int i = a; i <= b; i++)
{
cnt = 0;
memset(vis, 0, sizeof(vis));
if(!pre[i])
{
dfs(i);
if(cnt)
{
if(isprime[i] == 0)
cnt *= 2;
que.push(P(i, cnt));
}
}
}
if(que.empty())
{
cout << "SAD" << endl;
}
while(!que.empty())
{
cout << que.front().first << ' '
<< que.front().second << endl;
que.pop();
}
return 0;
}