ARC135 F - Delete 1, 4, 7, ...

看了好久题解的说

\(f^i(x)\) 为经历了 \(i\) 轮之后的 \(x\) 的为位置对于的初始下标。

那么有 \(f(x) = \lfloor\frac{3x+1}{2}\rfloor\)

\(f^i(x) = f(f(f()....)\)

考虑对这个柿子进行性质的观察。

我们最后只会剩余 \( frac{2n}{3}\) 个数,如果暴力则是 \(O(k(\frac{2}{3})^kn)\)
\(k\) 大时这个复杂度可以接受。

但是 \(k\) 小时,我们需要另辟蹊径。

我们发现 \(f^k(x + i2^k) = f^k(x) + i3^k\)

考虑设\(l + r = k\)

考虑折半跑路。

$f^k(x + i 2^r)= fl(fr(x) + i * 3^r) $

考虑\(g(a,j) = \sum^{2^j - 1}_{i = 0}f^l(a + i3^x)\)

我们考虑直接递推其,最后可以通过倍增和递归来处理出。

点击查看代码
#include <cstdio>
#include <unordered_map>
#pragma GCC optimize(2,3,"Ofast")
using namespace std;
typedef long long ll;
const int P=998244353;
ll n,res;int k;
ll f(ll x,int i){
	for(;i;--i) x=(3*x+1)/2;
	return x;
}
ll o[103],w[103],msk;
int L,R;
unordered_map<ll,int> mp[103];
int g(ll x,int i){
	if(x-1>msk) return (g(((x-1)&msk)+1,i)+(((x-1)>>L)%P)*(w[L]%P)%P*((1ll<<i)%P)%P)%P; //对内层的 a 进行 2^l 的平移
	if(!i) return mp[i][x]=f(x,L)%P;
	if(mp[i].find(x)!=mp[i].end()) return mp[i][x];
	return mp[i][x]=(g(x,i-1)+g(x+w[R]*(1ll<<(i-1)),i-1))%P;
}
int main(){
	scanf("%lld%d",&n,&k);
	o[0]=n;
	for(int i=1;i<=k;++i) o[i]=o[i-1]*2/3;
	if(k>40){//是的……需要数据分治……毒瘤
		int res=0;
		for(int i=1;i<=o[k];++i)
			res=(res+f(i,k))%P;
		printf("%d\n",res);
		return 0;
	}
	L=k/2;R=k-L;w[0]=1;msk=(1ll<<L)-1;
	for(int i=1;i<=30;++i) w[i]=w[i-1]*3;
	for(int i=1;i<=o[k]&&i<=(1ll<<R);++i){
		ll c=f(i,R),upb=((o[k]-i)>>R)+1;
		for(int j=50;~j;--j)
			if(upb>>j&1){
				res=(res+g(c,j))%P;
				c+=w[R]<<j; //对外层的 a 进行 2^r 的平移,拼接成一段前缀
			}
	}
	printf("%lld\n",res);
	return 0;
}
posted @ 2022-04-02 11:19  fhq_treap  阅读(107)  评论(0编辑  收藏  举报