题目链接:LibreOJ 不要62
解题思路:数位dp入门题目,数位dp是存在有模板的,可以通过一道题来领悟数位dp的思路。详细分析将放在代码中解释。
//#pragma GCC optimize(2)
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<ctime>
#include<cstring>
#include<list>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
int n, m;
int a[12]; //存一个数字的每一位
int dp[15][15]; //表示 (我们填到从右往左数第i位,当第i位填j的时候,i左边的位数全填原数字本身)有多少种合适的车牌
void init()
{
for (int i = 0; i <= 9; i++) dp[1][i] = 1; //个位初始条件,数位dp初始化
dp[1][4] = 0; //题目限制条件
for(int i=2;i<=10;i++) //枚举位数
for(int j=0;j<=9;j++) //枚举这一位放什么数字
for (int k = 0; k <= 9; k++)//枚举后一位的数字
{
//题目限制条件
if (j == 4 || k == 4)continue;
if (j == 6 && k == 2)continue;
dp[i][j] += dp[i - 1][k];
}
}
int res(int x)// 0~x的方案数
{
if (!x) return 1; //边界条件
mem(a, 0);
int le = 0; //x的长度
int ans = 0;
int last = 0; //上一位的数字
while (x) //肢解x
{
a[++le] = x % 10;
x /= 10;
}
/*这里是枚举每一位的数字来达到遍历0~x的效果*/
for (int i = le; i >= 1; i--) //从最高位开始枚举i
{
for (int j = 0; j < a[i]; j++) //枚举第i位可以放的数字0~a[i]-1,为什么不能等于a[i]呢?因为放a[i]的情况将放在下一次循环中被计算
{
if (j == 4)continue;
if (last == 6 && j == 2)continue;
ans += dp[i][j];
}
if (a[i] == 4)break;
if (a[i] == 2 && last == 6)break;
last = a[i];
if (i == 1)ans++; //加上之前漏掉的x他自己
}
return ans;
}
void solve()
{
init();
cin >> n >> m;
while (n && m)
{
cout << res(m) - res(n-1) << endl;
cin >> n >> m;
}
}
int main()
{
//std::ios::sync_with_stdio(false);
//cin.tie(0), cout.tie(0);
solve();
return 0;
}
思路:
1.根据题意初始化方案数
2.根据题意写出求解函数
3.主函数解决问题
作者:Avalon·Demerzel