• [SDOI/SXOI2022] 进制转换


    一、题目

    点此看题

    二、解法

    怎么根号分治成热门考点了,今年省选遍地走。

    本题的难点就是你要同时对两个进制规划,但实际上我们只能在线地考虑其中一个进制,另一个进制只能记录再状态中。暴力的 \(dp\) 方法是:设 \(f[i][j]\) 为从高到低考虑前 \(i\) 个三进制位,对应的二进制是 \(j\),转移暴力枚举当前填什么。

    考虑优化这个状态,我们想尽快确定二进制位上的值这样以后就不需要记录了。设 \(l_i\) 表示 \(3^i\) 最多影响后二进制的后 \(i\) 位,那么 \(j\) 的范围就限制在了 \([0,l_{i+1})\) 中,在 \(i\rightarrow i-1\) 的过程中,我们可以把 \([l_i,l_{i+1})\) 这些数位计算了。

    但是还可能存在进位问题,我们再记录 \(w\in\{0,1\}\) 表示后面的数位是否会进位给 \(l_i\),由于是给后面提出了要求,所以在 \(dp\) 过程中需要保证它成立。

    看似这个优化没有什么用,但是对于前 \(m/2\) 位,搜索带来的情况数只有 \(O(\sqrt n)\);对于后 \(m/2\) 位,状态被限制在了 \(O(\sqrt n)\) 的范围内。所以我们只对后 \(m/2\) 位记忆化,时间复杂度 \(O(\sqrt n)\)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    #define int long long
    const int M = 1<<11;
    const int MOD = 998244353;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,x,y,z,px[M][3],py[M],pz[M],f[1<<24][2];
    int m,l[M],s[M],bit[M],p[M],w[M];
    int qkpow(int a,int b)
    {
    	int r=1;
    	while(b>0)
    	{
    		if(b&1) r=r*a%MOD;
    		a=a*a%MOD;
    		b>>=1;
    	}
    	return r;
    }
    int dfs(int x,int ns,int nw,int u)
    {
    	if(x==-1) return nw?0:py[bit[ns]];
    	if(!u && x<m/2 && f[ns+s[x]][nw]!=-1)
    		return f[ns+s[x]][nw];
    	int r=0;
    	for(int i=0;i<3;i++) for(int tw=0;tw<2;tw++)
    	{
    		if(u && i>w[x]) continue;
    		int ts=ns+i*p[x]+(tw<<l[x]);
    		if((ts>=(1ll<<l[x+1]))!=nw) continue;
    		ts&=(1ll<<l[x+1])-1;
    		int A=px[x][i],B=py[bit[ts>>l[x]]],C=pz[i];
    		r=(r+dfs(x-1,ts&((1ll<<l[x])-1),tw,u&(i==w[x]))
    		*A%MOD*B%MOD*C%MOD)%MOD;
    	}
    	if(!u && x<m/2) f[ns+s[x]][nw]=r;
    	return r;
    }
    signed main()
    {
    	//freopen("conversion.in","r",stdin);
    	//freopen("conversion.out","w",stdout);
    	n=read();x=read();y=read();z=read();
    	py[0]=pz[0]=p[0]=1;
    	for(int i=1;i<(1<<10);i++)
    		bit[i]=bit[i>>1]+(i&1);
    	for(int i=1;i<=50;i++)
    		py[i]=py[i-1]*y%MOD,pz[i]=pz[i-1]*z%MOD;
    	while(n) w[m++]=n%3,n/=3;
    	for(int i=1;i<=m;i++) p[i]=p[i-1]*3;
    	for(int i=0;i<=m;i++)
    	{
    		px[i][0]=1;px[i][1]=qkpow(x,p[i]);
    		px[i][2]=px[i][1]*px[i][1]%MOD;
    		while((1ll<<l[i])<=p[i]) l[i]++;
    		if(i) s[i]=s[i-1]+(1ll<<l[i]);
    	}
    	memset(f,-1,sizeof f);
    	printf("%lld\n",(dfs(m-1,0,0,1)+MOD-1)%MOD);
    }
    
  • 相关阅读:
    spring整合mybatis错误:class path resource [config/spring/springmvc.xml] cannot be opened because it does not exist
    spring 整合Mybatis 《报错集合,总结更新》
    java_eclipse添加DID实现自动提示
    mbatis_逆向工程
    Spring《错误集合,总结更新》
    南山行 《重在坚持》
    mac OS 常用的一些快捷键
    object-c 语言特性@[] &@{}
    给textfield添加delegate的一种方法
    unwind segue
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/16292793.html
Copyright © 2020-2023  润新知