Description
给出以1为根的有根树,每个点上有个数字di (d1!=0)
定义一个包含1的连通块对应的数是其按编号从小到大做dfs序得到的序列中,di按顺序连接起来形成的数字
定义序列a,满足a1=1,ai=ai−1+maxdigit(ai−1)a_1=1,a_i=a_{i-1}+maxdigit(a_{i-1})a1=1,ai=ai−1+maxdigit(ai−1)
其中maxdigit(n)是n在十进制下最大的那个数位中的数
求有多少个包含1的连通块对应的数字在a中出现
n<=500
Solution
考虑如何判断一个数是否合法
定义F[i][p][x]表示当前数的后i位除个位全是0,个位为x,前面的最大值为p,使第i位产生1的进位之后个位会变成多少
F[i]可以从F[i-1]递归得到,加10个1就好了
那么我们也可以得到判定一个数是否合法的方法:一位一位放,记录最后一位,利用F不断跳
当然可以预处理trs[i][k][p][x]表示第i位放k,前面的位的最大值为p,个位为x,其余全为0,之后个位会变成什么
那么Dp的时候我们只需要记录i,p,x即可实现O(1)转移
考虑dfs序的限制,显然一个点是由dfs序上的一个区间转移过来的,用前缀和优化一下
复杂度O((n*10)^2)
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=505,Mo=1e9+7;
void inc(int &x,int y) {x=x+y>=Mo?x+y-Mo:x+y;}
int ty,n,x,y,a[N],nx[N][10][10],trs[N][10][10][10],to[N][N];
int f[N][N][10][10],sum[N][N][10][10];
int w[N],fa[N],sz[N],dfn[N],d[N],tot;
bool vis[10];
bool in(int n) {
a[0]=0;
for(;n;n/=10) a[++a[0]]=n%10;
int x=1,mx=0;
fd(i,a[0],1) {
x=trs[i][mx][a[i]][x];
mx=max(mx,a[i]);
}
return x!=-1;
}
void dfs(int x,int y) {
dfn[++tot]=x;sz[x]=1;fa[x]=y;w[x]=tot;
fo(i,1,to[x][0]) if (to[x][i]!=y) dfs(to[x][i],x),sz[x]+=sz[to[x][i]];
}
int main() {
fo(p,0,9)
fo(x,0,9) {
if (!p&&!x) continue;
int y=x;for(;y<10;y+=max(y,p));
nx[1][p][x]=y%10;
}
fo(i,2,500)
fo(p,0,9)
fo(x,0,9) {
if (!p&&!x) continue;
int y=x;
fo(j,0,9) y=nx[i-1][max(p,j)][y];
nx[i][p][x]=y;
}
fo(i,1,500)
fo(p,0,9)
fo(x,0,9) {
if (!p&&!x) continue;
if (i>1) {
int y=x;
trs[i][p][0][x]=y;
fo(j,0,8) {
y=nx[i-1][max(p,j)][y];
trs[i][p][j+1][x]=y;
}
} else {
int y=x;
fo(j,0,9) vis[j]=0;
for(;y<10;y+=max(y,p)) vis[y]=1;
fo(j,0,9)
if (vis[j]) trs[i][p][j][x]=j;
else trs[i][p][j][x]=-1;
}
}
for(scanf("%d",&ty);ty;ty--) {
scanf("%d",&n);
fo(i,1,n) to[i][0]=0;
fo(i,1,n-1) {
scanf("%d%d",&x,&y);
to[x][++to[x][0]]=y;
to[y][++to[y][0]]=x;
}
fo(i,1,n) sort(to[i]+1,to[i]+to[i][0]+1);
fo(i,1,n) scanf("%d",&d[i]);
tot=0;dfs(1,0);
int ans=0;
fo(i,1,n) fo(j,1,n-i+1) fo(p,0,9) fo(x,0,9) f[i][j][p][x]=sum[i][j][p][x]=0;
fo(i,1,n) if (trs[i][0][d[1]][1]!=-1) f[1][i][d[1]][trs[i][0][d[1]][1]]=sum[1][i][d[1]][trs[i][0][d[1]][1]]=1;
fo(i,2,n) {
fo(j,1,n-i+1)
fo(p,0,9)
fo(x,0,9) {
int y=dfn[i];
if (trs[j][p][d[y]][x]!=-1) inc(f[i][j][max(d[y],p)][trs[j][p][d[y]][x]],(sum[i-1][j+1][p][x]-sum[w[fa[y]]-1][j+1][p][x]+Mo)%Mo);
}
fo(j,1,n-i+1) fo(p,0,9) fo(x,0,9) sum[i][j][p][x]=(sum[i-1][j][p][x]+f[i][j][p][x])%Mo;
}
fo(i,1,n) fo(p,0,9) fo(x,0,9) inc(ans,f[i][1][p][x]);
printf("%d\n",ans);
}
return 0;
}