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

    题目描述

    luogu
    不含前导零且相邻两个数字之差至少为 2 的正整数被称为 windy 数。windy 想知道,在 \(a\)\(b\) 之间,包括 \(a\)\(b\) ,总共有多少个 windy 数?

    数据范围: \(1\leq a\leq b\leq 2×10^9\)

    solution

    一道很经典的数位dp题。

    首先,我们可以预处理出 \(1-a\) 以及 \(1-b\) 之间的windy数,之后两者的差,就是答案。

    设: \(f[i][j]\) 表示长度为 \(i\) 且最高位为 \(j\) 的 windy 数的个数。

    这个可以先预处理出来。

    void YYCH()
    {
    	for(int i = 0; i <= 9; i++) f[1][i] = 1;//初始化,当只有一位时,所有的数都是windy数
    	for(int i = 2; i <= 10; i++)//枚举位数
    	{
    		for(int j = 0; j <= 9; j++)//枚举最高位的数字
    		{
    		    for(int k = 0; k <= 9; k++)//枚举次高位上的数字
    		    {
    		    	if(abs(j-k) >= 2)
    		    	{
    		    		f[i][j] += f[i-1][k];//f[i][j]表示i位数且最高位为j的情况
    		    	}
    		    }
    		}
    	}
    }
    

    之后求 \(1-a\) 之间的 \(windy\) 数的个数时,根据 \(a\) 的每一位大小,分类讨论一下即可。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define LL long long
    LL a,b;
    LL f[15][10], shuwei[15];
    inline LL read()
    {
    	int s = 0, w = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
    	return s * w; 
    }
    void YYCH()//预处理
    {
    	for(int i = 0; i <= 9; i++) f[1][i] = 1;
    	for(int i = 2; i <= 10; i++)
    	{
    		for(int j = 0; j <= 9; j++)
    		{
    			for(int k = 0; k <= 9; k++)
    		    {
    		    	if(abs(j-k) >= 2)
    		    	{
    		    		f[i][j] += f[i-1][k];
    		    	}
    		    }
    		}
    	}
    }
    LL calc(LL a)//统计答案
    {
    	LL ans = 0, len = 0, x = a;
    	while(x)//把a的每一位都提取出来
    	{
    		len++;
    		shuwei[len] = x % 10;
    		x /= 10;
    	}
    	for(int i = 1; i < len; i++)//先加上不满len位的数
    	{
    		for(int j = 1; j <= 9; j++)
    		{
    			ans += f[i][j];
    		}
    	}
    	for(int i = 1; i < shuwei[len]; i++) ans += f[len][i];//加上最高位比a要小的数
    	for(int i = len-1; i >= 1; i--)//枚举下一位
    	{
    		for(int j = 0; j < shuwei[i]; j++)//枚举下一位上的数字
    		{
    			if(abs(shuwei[i+1]-j) >= 2) ans += f[i][j];
    		}
    		if(abs(shuwei[i+1]-shuwei[i]) < 2) break;//如果当前已经不满足windy数的性质,那么接下来的的数位,无论填什么都不会是windy数
    	}
    	return ans;
    }
    int main()
    {
    	YYCH();
    	a = read(); b = read();
    	printf("%lld\n",calc(b+1)-calc(a));
    }
    
    
  • 相关阅读:
    Ubuntu 杂音 alsa*
    安装YouCompleteMe
    vimrc
    Linux Windows 修改键盘映射
    VMware Workstation+Linux+Xshell+Xftp+MySQL+SQLyog 配置
    leetcode Merge Intervals
    leetcode Remove Duplicates from Sorted Array II
    用栈实现二叉树的非递归中序遍历
    nth_element 测试程序
    Windows 程序设计
  • 原文地址:https://www.cnblogs.com/genshy/p/13443991.html
Copyright © 2011-2022 走看看