You are given a positive integer nn. Let's call some positive integer aa without leading zeroes palindromic if it remains the same after reversing the order of its digits. Find the number of distinct ways to express nn as a sum of positive palindromic integers. Two ways are considered different if the frequency of at least one palindromic integer is different in them. For example, 5=4+15=4+1 and 5=3+1+15=3+1+1 are considered different but 5=3+1+15=3+1+1 and 5=1+3+15=1+3+1 are considered the same.
Formally, you need to find the number of distinct multisets of positive palindromic integers the sum of which is equal to nn.
Since the answer can be quite large, print it modulo 109+7109+7.
Input
The first line of input contains a single integer tt (1≤t≤1041≤t≤104) denoting the number of testcases.
Each testcase contains a single line of input containing a single integer nn (1≤n≤4⋅1041≤n≤4⋅104) — the required sum of palindromic integers.
Output
For each testcase, print a single integer denoting the required answer modulo 109+7109+7.
Example
input
Copy
2 5 12
output
Copy
7 74
Note
For the first testcase, there are 77 ways to partition 55 as a sum of positive palindromic integers:
- 5=1+1+1+1+15=1+1+1+1+1
- 5=1+1+1+25=1+1+1+2
- 5=1+2+25=1+2+2
- 5=1+1+35=1+1+3
- 5=2+35=2+3
- 5=1+45=1+4
- 5=55=5
For the second testcase, there are total 7777 ways to partition 1212 as a sum of positive integers but among them, the partitions 12=2+1012=2+10, 12=1+1+1012=1+1+10 and 12=1212=12 are not valid partitions of 1212 as a sum of positive palindromic integers because 1010 and 1212 are not palindromic. So, there are 7474 ways to partition 1212 as a sum of positive palindromic integers.
思路:刚开始时没有读明白题,没明白啥意思,后来才知道组成它的数是回文数即可。那么我们是不是只要通过预处理出哪个数回文的哪个数不是回文,然后让这些回文数进行组合成我们需要的数是不是就可以了。回文数:只要把这个数颠倒过来还是原来的那个数就是回文数。留下的回文数不就是让我们任意挑选的,只要相加不超过我们需要的那个数即可,这是不是就变成了选数选物品的问题了,这不就是完全背包问题了。
int转化为字符串:to_string方法
一维压缩dp数组,可以很好解决预处理问题,也就是不知道物品数量时(但是开到不越界的二维也是行的)
背包问题:
01背包:
//二维写法
for(int i=1;i<=n;i++)
{
for(int j=0;j<=v;j++)
{
f[i][j]=f[i-1][j];
if(a[i]<=j)
{
f[i][j]=max(f[i][j],f[i-1][j-a[i]]+w[i]);
}
}
}
//一维写法
for(int i=1;i<=n;i++)
{
for(int j=m;j>=a[i];j--)
{
f[j]=max(f[j],f[j-a[i]]+w[i]);
}
}
二维的不用考虑遍历的顺序(任何),为什么在压缩到一维后,第二层必须要倒着遍历呢?是因为防止多个相同物品的插入。例如:weight[0]=1 , value[0]=15。那么 f[1] = f[1-weight[0]] + value[0] = 15 , f[2] = f[2-weight[0]] + value[0] = 15+15=30.也就是在 j 循环扩大时,会不断多次选择这个较小的数,就会变成完全背包。可是当我们倒着遍历时:f[2] = f[2-weight[0]] + value[0] =15 , f[1] = f[1-weight[0]] + value[0] = 15 ,这样每一次的选择都是一个新的 f 数组,不会多次选择,不会用上一个的值来影响当前的数。一维01背包倒着遍历。(为什么会有 f[i-1][j-x]+w 因为这个物品只能选一次,加上 w[i] 时就已经证明要选这个数了,而完全背包不会,只需要注意体积就行了)
完全背包:
//二维写法
for(int i=1;i<=n;i++)
{
for(int j=0;j<=v;j++)
{
f[i][j]=f[i-1][j];
if(a[i]<=j)
{
f[i][j]=max(f[i][j],f[i][j-a[i]]+w[i]);
}
}
}
//一维写法
for(int i=1;i<=n;i++)
{
for(int j=0;j<=v;j++)
{
f[j]=max(f[j],f[j-a[i]]+w[i]);
}
}
选无数次正着遍历,只能选一次的倒着遍历不受影响。
完整代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
const int N=4e4+10;
int f[N];
vector<int>v;
void solve()
{
string s,t;
for(int i=1;i<=40000;i++)
{
s=to_string(i);
t=s;
reverse(t.begin(),t.end());
if(s==t)v.push_back(i);
}
int len=v.size();
f[0]=1;
for(int i=1;i<=len;i++)
{
int x=v[i-1];
for(int j=x;j<=40000;j++)
{
f[j]=(f[j]+f[j-x])%mod;
}
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin>>t;
solve();
while(t--)
{
int n;
cin>>n;
cout<<f[n]<<endl;
}
return 0;
}