题解:P9328 [CCC 2023 S5] The Filter
题解
-
很妙的一道题。
首先为了减小精度误差,我们将所有数据乘上
然后我们需要发现筛子的两个重要性质:
- 所有筛子关于中心对称,所以点
i 和点N-i 一定同被筛去或同时保留。 - 若点
x (x<\dfrac{N}{3}) 被第k 层的筛子筛去,那么点3x 必然被第k-1 层的筛子筛去,反之亦然。
性质一显而易见,性质二大家可以通过把第
结合以上两条性质,构造函数
- 如果
x 会被筛去,那么在若干次递归后他必定会落在第一层的筛子内。 - 如果
x 不会被筛去,那么每次递归查询的数形成的队列x,f(x),f(f(x)),f(f(f(x))) ...... 必定会出现循环节,只要在第一次某个数重复出现时跳出即可。
对于子任务 2,因为
发现当
时间复杂度
代码
#include<bits/stdc++.h>
#define mkp make_pair
using namespace std;
const int N=1e7;
unordered_map<int,int> mp;
int n,head,tail=1;
long long L,R;
double X[N],Y[N];
inline int dfs(int i)
{
if(mp[i])return mp[i];
if(i>L&&i<R)return mp[i]=1;
mp[i]=2;
return mp[i]=dfs(min(i,n-i)*3);
}
void Solve(double l,double r)
{
if(r-l<1.0)
{
for(int i=ceil(l);i<=r;i++)
if(dfs(i)==2)printf("%d\n",i);
return;
}
double x=l+(r-l)/3,y=r-(r-l)/3;
X[++tail]=l;Y[tail]=x;
X[++tail]=y;Y[tail]=r;
}
signed main()
{
cin>>n;
L=n/3;R=(2ll*n-1)/3+1;
X[1]=0.0;Y[1]=1.0*n;
while(head<tail){head++;Solve(X[head],Y[head]);}
return 0;
}