把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P8350 [SDOI/SXOI2022] 进制转换

题面传送门

首先题面中那个\(y=1\)的数位dp部分分是诈骗,这题和数位dp没有半毛钱关系。

为啥SDOI两个T2都是算法诈骗题啊

首先考虑一个爆搜,爆搜三进制每一位是什么,然后转化成二进制。这个复杂度显然是\(O(n)\)的,不可接受。

但是实际上可以优化,我们考虑对于一个较低位的三进制数,其能影响的二进制的最高位数有限,因此考虑根号分治。设定阈值\(B1,B2\)表示三进制下除了后\(B1\)位外的数爆搜,后\(B1\)位的数只会影响二进制下\(B2\)范围内的数。后面就可以有\(O(B2\log n)\)的dp可以解决。

实际实现的时候取\(B1=13,B2=21\)即可,时间复杂度差不多是\(O(\sqrt n)\),但是跑得非常慢。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=(1<<21)+5,M=13,M1=pow(3,13),M2=28,K=1e5+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int X,Y,z,A[30];ll f[N][2][2],g[N][2][2],Po[30],Z[3],n,Ps[30][3],Ans,Ys[30];
ll mpow(ll x,ll y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
void calc(ll w,int op,ll Ts){int i,p=w&((1<<21)-1);f[p][op][0]=(f[p][op][0]+Ts*Ys[__builtin_popcount(w>>21)])%mod;f[p][op][1]=(f[p][op][1]+Ts*Ys[__builtin_popcount((w>>21)+1)])%mod;}
void dfs(int x,ll w,int op,ll Ts){if(x==12) return calc(w,op,Ts);for(int i=0;i<=(op?A[x]:2);i++) dfs(x-1,w+Po[x-1]*i,i==A[x]&&op,Ts*Ps[x][i]%mod);}
int main(){
	freopen("1.in","r",stdin);
	int i,j,x,y,op;scanf("%lld%d%d%d",&n,&X,&Y,&z);for(Po[0]=i=1;i<=M2;i++) Po[i]=Po[i-1]*3,A[i]=n%Po[i]/Po[i-1],Ps[i][0]=1,Ps[i][1]=mpow(X,Po[i-1])*z%mod,Ps[i][2]=mpow(X,Po[i-1]*2)*z%mod*z%mod;
	for(Ys[0]=i=1;i<=29;i++) Ys[i]=Ys[i-1]*Y%mod;dfs(M2,0,1,1);for(i=12;i;i--){
		Mc(g,f);Me(f,0);for(j=0;j<(1<<21);j++){
			for(x=0;x<2;x++){
				for(y=0;y<2;y++){if(!g[j][x][y]) continue;if(y&&j+Po[i]-1<(1<<21)) continue;
					for(op=0;op<=(x?A[i]:2);op++){//cerr<<i<<' '<<j<<' '<<x<<" "<<y<<' '<<g[j][x][y]<<'\n';
						if(j+op*Po[i-1]>=(1<<21)) {if(y) f[j+op*Po[i-1]-(1<<21)][x&&op==A[i]][0]=(f[j+op*Po[i-1]-(1<<21)][x&&op==A[i]][0]+g[j][x][y]*Ps[i][op])%mod;}
						else {f[j+op*Po[i-1]][x&&op==A[i]][y]=(f[j+op*Po[i-1]][x&&op==A[i]][y]+g[j][x][y]*Ps[i][op])%mod;}
					}
				}
			}
		}
	}for(i=0;i<(1<<21);i++) for(j=0;j<2;j++)Ans+=f[i][j][0]*Ys[__builtin_popcount(i)]%mod;printf("%lld\n",(Ans-1)%mod);
}
posted @ 2022-09-09 19:40  275307894a  阅读(85)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end