zoukankan      html  css  js  c++  java
  • P2657 [SCOI2009] windy 数

    题面

    windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,

    在A和B之间,包括A和B,总共有多少个windy数?

    输入输出格式

    输入格式:

    包含两个整数,A B。

    输出格式:

    一个整数

    输入输出样例

    输入样例#1:

    1 10
    

    输出样例#1:

    9
    

    输入样例#2:

    25 50
    

    输出样例#2:

    20
    

    说明

    100%的数据,满足 1 <= A <= B <= 2000000000 。

    题解

    本题套上一个数位(dp)的板子,定义状态(f[i][j])表示第(i)位为数字(j)时的合法个数

    由于本题的约数条件是相邻两位数字之差不小于2(且所有个位数均视为满足条件),直接套板子肯定有问题,因为我们必须去处理前导零的问题

    根据套路的,我们加上一个前导零(lead)

    那么每次枚举当前位数字时,判断一下上一位是否受(lead)的限制且当前位是0,是的话就说明这时存在前导0,往后搜索时将pre赋值成-2.然后这样(0-(-2)>=2)

    然后将所有不受限制的情况都记忆化一下,最后前缀和思想相减一下就行

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll dp[15][15],ans;//dp[i][j]表示搜到第i位,前一位是j,的!limit方案totnum;
    int a[15],len;
    long long L,R;
    ll dfs(int pos,int pre,int st,int limit)//pos当前位置,pre前一位数,st判断前面是否全是0,limit最高位限制 
    {
    	if(pos>len) return 1;//搜完了 
    	if(!limit&&dp[pos][pre]!=-1) return dp[pos][pre];//没有最高位限制,已经搜过了
    	ll ret=0;
    	int res=limit?a[len-pos+1]:9;//当前位最大数字 
    	for(int i=0;i<=res;i++)//从0枚举到最大数字 
    	{
    		if(abs(i-pre)<2) continue;//不符合题意,继续 
    		if(st&&i==0) ret+=dfs(pos+1,-2,1,limit&&i==res);//如果有前导0,下一位随意 
    		else ret+=dfs(pos+1,i,0,limit&&i==res);//如果没有前导0,继续按部就班地搜 
    	}
    	if(!limit&&!st) dp[pos][pre]=ret;//没有最高位限制且没有前导0时记录结果 
    	return ret;
    }
    void part(ll x)
    {
    	len=0;
    	while(x) a[++len]=x%10,x/=10;
    	memset(dp,-1,sizeof dp);
    	ans=dfs(1,-2,1,1);
    }
    int main()
    {
        scanf("%lld%lld",&L,&R);
        part(L-1);ll minn=ans;
    	part(R);  ll maxx=ans;
    	printf("%lld",maxx-minn);
    	return 0;
    }
    
  • 相关阅读:
    C#连接数据库的三种方法
    远程控制mysql出现的问题
    DFS_子集
    DFS_全排列
    Centos下搭建Mysql
    Nginx与PHP(FastCGI)的安装、配置与优化
    Centos下主DNS的搭建
    Nginx的基本配置与优化
    Nginx服务器的安装与配置
    gdb基本命令
  • 原文地址:https://www.cnblogs.com/bangdexuanyuan/p/14020257.html
Copyright © 2011-2022 走看看