Codeforces-1673 C: Palindrome Basis
题目传送门:Codeforces-1673 C
题目
题目截图
样例描述
题目大意
镜像数为将里面的数字符反转后,与原数一样的数。给定一个数 n n n,问它可以由多少种不同的镜像数求和得到。当两个组合中某个数出现的次数不同时,认为它们是不同的组合。
题目解析
首先我们注意到,输入的
n
n
n 很小,一共只有五位数,这意味着小于
n
n
n 的镜像数最多也就几百个。那么首先,我们可以暴力得到所有的镜像数。
之后我们使用
d
p
dp
dp 来解决这个问题。我们考虑不断向组合中加入新的数,设
d
p
i
,
j
dp_{i,j}
dpi,j 代表由前
j
j
j 个镜像数组合得到数
i
i
i 的组合数。转移方程可以写为
d
p
i
,
j
=
d
p
i
,
j
−
1
+
d
p
i
−
p
[
j
]
,
j
dp_{i,j}=dp_{i,j-1} + dp_{i-p[j],j}
dpi,j=dpi,j−1+dpi−p[j],j,即,要么数
i
i
i 可以只从前
j
−
1
j-1
j−1 个镜像数组合得到;要么可以使用前
j
j
j 个镜像数组合
i
−
p
[
j
]
i-p[j]
i−p[j](
p
[
j
]
p[j]
p[j] 是第
j
j
j 小的镜像数),之后再加上一个
p
[
j
]
p[j]
p[j], 得到。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e4 + 7;
const int mod = 1e9 + 7;
vector<int> palind;
int dp[maxn][500];
bool check(int x) {
vector<int> dig;
while(x > 0) {
dig.push_back(x % 10);
x /= 10;
}
for(int l=0, r=dig.size()-1; l < r; ++l, --r)
if(dig[l] != dig[r]) return false;
return true;
}
int main() {
int t, n;
for(int i=1; i<maxn; ++i)
if(check(i)) palind.push_back(i);
for(int i=0; i<palind.size(); ++i) dp[1][i] = dp[0][i] = 1;
for(int i=1; i<maxn; ++i) {
dp[i][0] = 1;
for(int j=1; j<palind.size(); ++j)
if(i >= palind[j]) dp[i][j] = (dp[i][j-1] + dp[i-palind[j]][j]) % mod;
else dp[i][j] = dp[i][j-1];
}
cin >> t;
while(t--) {
cin >> n;
cout << dp[n][palind.size()-1] << endl;
}
return 0;
}