zoukankan      html  css  js  c++  java
  • 【一天一DP计划】数位dp

    入坑之好博

    一本通 数位DP

    浅谈数位DP

    ## P4127 同类分布

    现在关键的问题是:怎样记录dp状态?

    这里 st可达到 1e18 显然是不能作为dp转移的下标直接记录的

    所以我们考虑取模

    我们最理想的模数当然是把每次搜到最后得到的数字各个位数之和

    但是我们发现在这个过程中 sum是发生变化的

    所以我们就应该以一个定值作为模数

    那好,我们虽然不知道最后各位之和的结果,我们枚举总可以吧

    我们只需要枚举所有的各位数字之和作为模数

    最后判断 sum 和枚举的 mod相等并且 st%sum=0 的数就是符合题意的答案

    /*
    reference:
    	https://www.luogu.org/blog/virus2017/p4127#
    date:
    	2019.10.03
    solution:
    	- 既然st的范围是1e18那么long long都存不下肯定不能记为dp的状态
    		- 那么肯定要取模!模数为什么呢 ?最好为当前模数和sum
    			- 可是sum在转移的时候一直在改变,那么之前记录的dp状态就无效了!
    				- 那我们换个思路,模数呢最大为18*9,那我们枚举每个模数,判断当前在这个模数意义下是否合法
    					- 合法的条件:sum==mod && st==0(st要一直%mod) 
    */
    int a,b,len,mod; 
    int dp[18+5][18*9+5][18*9+5],bit[18+5];
    
    inline int dfs(int pos,int sum,int st,int limit){
    	if(pos>len && sum==0)return 0; 
    	if(pos>len)return sum==mod && st==0;
    	if(!limit && dp[pos][sum][st]!=-1)return dp[pos][sum][st];
    	int high=limit?bit[len-pos+1]:9;
    	int res=0;
    	rep(i,0,high){
    		res+=dfs(pos+1,sum+i,(10ll*st+i)%mod,i==high && limit);
    	}
    //	return limit?res:dp[pos][sum][st]=res;
    	if(!limit)dp[pos][sum][st]=res;
    	return res;
    }
    
    inline int work(int x){
    	len=0;
    	while(x){
    		bit[++len]=x%10;
    		x/=10;
    	}
    	int res=0;
    	for(mod=1;mod<=len*9;++mod){
    		mem(dp,-1);
    		res+=dfs(1,0,0,1);
    	}
    	return res;
    }
    
    #undef int
    int main(){
    #define int long long
    	freopen("tonglei.txt","r",stdin);
    	rd(a),rd(b);
    	printf("%lld",work(b)-work(a-1)); 
    	return 0;
    }
    

    ##windy数

    /*
    reference:
    	https://www.luogu.org/blog/virus2017/solution-p2657
    date:
    	2019.10.03
    solution:
    	最妙:考虑前导零的时候,第一位的时候,0和1是没办法取到的,因为abs(i-pre)<2了,
    	那么,就等价于,pre设为-2问题解决 
    */
    int a,b,len;
    int bit[15],dp[15][15];
    
    inline int dfs(int pos,int pre,int lead,int limit){
    	if(pos>len)return 1;
    	if(!limit && dp[pos][pre]!=-1)return dp[pos][pre];
    	int high=limit?bit[len-pos+1]:9;
    	int res=0;
    	rep(i,0,high){
    		if(abs(i-pre)<2)continue;
    		else if(lead && i==0)
    			res+=dfs(pos+1,-2,1,i==high && limit);
    		else
    			res+=dfs(pos+1,i,0,i==high && limit);
    	}
    	if(!limit && !lead)dp[pos][pre]=res;
    	return res;
    }
    
    inline int work(int x){
    	len=0;
    	while(x){
    		bit[++len]=x%10;
    		x/=10;
    	}
    	mem(dp,-1);
    	return dfs(1,-2,1,1);
    }
    
    #undef int
    int main(){
    #define int long long
    	#ifdef WIN64
    	freopen("windy.txt","r",stdin);
    	#endif
    	rd(a),rd(b);
    	printf("%lld
    ",work(b)-work(a-1));
    	return 0;
    }
    

    ##数字计数(求不降数)

    /*
    int a,b,len,mod;
    int bit[15],dp[15][15];
    
    inline int dfs(int pos,int pre,int limit){
    	if(pos>len)return 1;
    	if(dp[pos][pre]!=-1 && !limit)return dp[pos][pre];
    	int high=limit?bit[len-pos+1]:9;
    	int res=0;
    	rep(i,pre,high){
    		res+=dfs(pos+1,i,i==high && limit);
    	}
    	if(!limit)dp[pos][pre]=res;
    	return res;
    }
    
    inline int work(int x){
    	len=0;
    	while(x){
    		bit[++len]=x%10;
    		x/=10;
    	}
    	mem(dp,-1);
    	return dfs(1,0,1);
    } 
    #undef int
    int main(){
    #define int long long
    	#ifdef WIN64
    	freopen("shuzi2.txt","r",stdin);
    	#endif
    	while(~scanf("%lld%lld",&a,&b)){
    		printf("%lld
    ",work(b)-work(a-1));
    	}
    	return 0;
    }
    

    ##不要62

    /*
    int a,b,len;
    int bit[10],dp[10][15];
    
    inline int dfs(int pos,int pre,int limit){
    	if(pos>len)return 1;
    	if(dp[pos][pre]!=-1 && !limit)return dp[pos][pre];
    	int high=limit?bit[len-pos+1]:9;
    	int res=0;
    	rep(i,0,high){
    		if(i==4)continue;
    		if(pre==6 && i==2)continue;
    		res+=dfs(pos+1,i,i==high && limit);
    	}
    	if(!limit)dp[pos][pre]=res;
    	return res;
    }
    
    inline int work(int x){
    	mem(bit,0);
    	len=0;
    	while(x){
    		bit[++len]=x%10;
    		x/=10;
    	}
    	mem(dp,-1);
    	return dfs(1,0,1);
    }
    
    #undef int
    int main(){
    #define int long long
    	#ifdef WIN64
    	freopen("62.txt","r",stdin);
    	#endif
    	while(1){
    		rd(a),rd(b);
    		if(a==0 && b==0)break; 
    		printf("%lld
    ",work(b)-work(a-1));
    	}
    	return 0;
    }
    

    ##数字游戏(取模)

    int a,b,len,mod;
    int bit[15],dp[15][900];
    
    inline int dfs(int pos,int sum,int limit){
    	if(pos>len)return sum==0?1:0;
    	if(!limit && dp[pos][sum]!=-1)return dp[pos][sum];
    	int high=limit?bit[len-pos+1]:9;
    	int res=0;
    	rep(i,0,high){
    		res+=dfs(pos+1,(sum+i)%mod,i==high && limit);
    	}
    	if(!limit)dp[pos][sum]=res;
    	return res;
    }
    
    inline int work(int x){
    	len=0;
    	while(x){
    		bit[++len]=x%10;
    		x/=10;
    	}
    	mem(dp,-1);
    	return dfs(1,0,1);
    }
    
    #undef int
    int main(){
    #define int long long
    	#ifdef WIN64
    	freopen("shuzi.txt","r",stdin);
    	#endif
    	while(~scanf("%lld%lld%lld",&a,&b,&mod)){
    		printf("%lld
    ",work(b)-work(a-1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    java实现获取当前年月日 小时 分钟 秒 毫秒
    四种常见的 POST 提交数据方式(application/x-www-form-urlencoded,multipart/form-data,application/json,text/xml)
    Cannot send, channel has already failed:
    Java 枚举(enum) 详解7种常见的用法
    C语言指针详解(经典,非常详细)
    ActiveMQ进阶配置
    Frame size of 257 MB larger than max allowed 100 MB
    SpringJMS解析--监听器
    SpringJMS解析-JmsTemplate
    delphi 修改代码补全的快捷键(由Ctrl+Space 改为 Ctrl + alt + Space)
  • 原文地址:https://www.cnblogs.com/sjsjsj-minus-Si/p/11634654.html
Copyright © 2011-2022 走看看