【问题描述】
windy定义了一种windy数。
不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。
windy想知道,在A和B之间,包括A和B,总共有多少个windy数?
【输入格式】
输入文件windy.in包含两个整数,A B。
【输出格式】
输出文件windy.out包含一个整数。
【输入样例一】
1 10
【输出样例一】
9
【输入样例二】
25 50
【输出样例二】
20
【数据规模和约定】
20%的数据,满足 1 <= A <= B <= 1000000 。
100%的数据,满足 1 <= A <= B <= 2000000000 。
此题为数字统计型问题。首先一个动态规划:
用f[i][j]表示最高位为j(包括前导0)的(i+1)位数中所有windy数的总数。
f[i][j] = sigma(|k-j| >= 2) {f[i - 1][k]}。
___________________
设要求的区间为[0, a(n-1)a(n-2)...a1a0)。
那么,分为以下几步求解:
_____________
1) 求出[0,a(n-1)00...00)中windy数的个数即
sigma(i = 0; i < n-1; ++i) sigma(j = 1; j < 10; ++j) {f[i][j]}
_____________ ___________________
2) 求出[a(n-1)00...00, a(n-1)a(n-2)00...00)中windy的个数即
_____________
[0, a(n-2)00...00)且满足10^(n-2)位上的数与较高一位之差的绝对值大于等于2。
可先将当前最高位去掉,并将n自减1,然后重复步骤2),直到该数变成0为止。
提交情况:共提交5次。
第一次0分,WrongAnswer * 10。
第二次20分,WrongAnswer * 8。
第三次40分,WrongAnswer * 6。
第四次80分,WrongAnswer * 2。
第四次100分。
ACCode(C风格):
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
int f[20][20];
int A, B;
char a[20], b[20];
int calc(char *s)
{
int len = strlen(s), ans = 0;
std::reverse(s, s + len);
for (int i = 0; i < len; ++i)
s[i] -= '0';
for (int i = 0; i < len - 1; ++i)
for (int j = 1; j < 10; ++j)
ans += f[i][j];
for (int j = 1; j < s[len - 1]; ++j)
ans += f[len - 1][j];
for (int i = len - 2; i > -1; --i)
{
for (int j = 0; j < s[i]; ++j)
if (abs(j - s[i + 1]) > 1)
ans += f[i][j];
if (abs(s[i] - s[i + 1]) < 2)
//若当前数位和较高一位数字相差大于1则可直接退出。
{
std::reverse(s, s + len);
for (int i = 0; i < len; ++i)
s[i] += '0';
return ans;
} //
}
std::reverse(s, s + len);
for (int i = 0; i < len; ++i)
s[i] += '0';
return ans;
}
int main()
{
freopen("windy.in", "r", stdin);
freopen("windy.out", "w", stdout);
scanf("%d%d", &A, &B);
sprintf(a, "%d", A);
sprintf(b, "%d", ++B);
for (int j = 0; j < 10; ++j) f[0][j] = 1;
for (int i = 1; i <= strlen(b); ++i)
for (int j = 0; j < 10; ++j)
for (int k = 0; k < 10; ++k)
if (abs(j - k) > 1)
f[i][j] += f[i - 1][k];
printf("%d\n", calc(b) - calc(a));
return 0;
}
ACCode(C++风格):
#include <fstream>
#include <sstream>
#include <cstring>
#include <algorithm>
std::stringstream ss;
int f[20][20], A, B;
std::string a, b;
int calc(std::string s)
{
if (s == "0") return 0;
int sz = s.size(), ans = 0;
reverse(s.begin(), s.end());
for (int i = 0; i < sz - 1; ++i)
for (int j = 1; j < 10; ++j)
ans += f[i][j];
for (int j = '1'; j < s[sz - 1]; ++j)
ans += f[sz - 1][j - '0']; //
for (int i = sz - 2; i > -1; --i)
{
for (int j = '0'; j < s[i]; ++j)
if (abs(j - s[i + 1]) > 1)
ans += f[i][j - '0'];
if (abs(s[i] - s[i + 1]) < 2)
return ans;
}
return ans;
}
int main()
{
std::ifstream cin("windy.in");
cin >> A >> B;
cin.close();
ss << A;
ss >> a;
ss.clear();
ss << ++B;
ss >> b;
ss.clear();
for (int j = 0; j < 10; ++j) f[0][j] = 1;
for (int i = 1; i <= b.size(); ++i)
for (int j = 0; j < 10; ++j)
for (int k = 0; k < 10; ++k)
if (abs(j - k) > 1)
f[i][j] += f[i - 1][k];
std::ofstream cout("windy.out");
cout << calc(b) - calc(a) << std::endl;
cout.close();
return 0;
}