C. Palindrome Basis - DP


C. Palindrome Basis

https://codeforces.ml/contest/1673/problem/C

题意

给你一个数 问你一共有多少种不同的组合 可以实现若干个回文数字相加得到这个数

思路

数据不超过4e4 而对于4e4之内的回文数字 最多不超过500 (一位数回文数有9个 两位的9个 三位的90个 四位的90个 5位的有300个 一共就489个)
4e4+500的复杂度可以被接受
可以转换为简单的dp
dp[i][j] 代表数字i 只由前j个回文数组合的方法数
那么转移方程就可以是: $$dp[i][j] = dp[i - pa[j]][j] + dp[i][j - 1]$$

#include
#include
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
 
const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-4;
const int N = 4e4 + 10;
const int M = 1e5 + 5;
const int mod = 1e9 + 7;
ll n, m, dp[N][505], pa[40010];
//判断是否为回文串 
bool isp(ll x) {
	ll xx = 0, nn = x;
	while (x > 0) {
		xx = x % 10 + xx * 10;
		x /= 10;
	}
	if (xx == nn) return true;
	else return false;
}
 
void solve()
{
	cin >> n;
	cout << dp[n][500] << "\n";
}
 
signed main()
{
	IOS;
	ll tot = 0;
	for(int i = 1; i <= 40005; i++){
		if (isp(i)) pa[++tot] = i;
    }
	for (int i = 1; i <= 500; i++) {
		dp[0][i] = 1;//开始初始化 
	}
	for (int i = 1; i <= 40005; i++) {//遍历所有数
		for (int j = 1; j <= 500; j++) {//遍历用到回文数的个数
			if (pa[j] <= i) dp[i][j] = (dp[i][j - 1] + dp[i - pa[j]][j]) % mod;
			else dp[i][j] = dp[i][j - 1];
		}
	}
	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}