传送门.

题解:


最主要的问题是如何判断一个数是否合法,这就需要发现性质了。

这个状态划分还是不太容易想到,

每次加的数\(∈[0,k)\),也就是个位一直在变变变,更高的位每次都是加一,这启发我们状态的划分。

这个时候可以利用数位dp的逐位确定思想,在尝试后,发现可以从高位到低位,因为当高位确定后,高位就不会变了,那么高位的最大值也就确定了。

设\(f[i][p][a]\),\(i\)含义如上,\(i+1\)位后的最大值是p,\(2-i\)位是0,当前个位是\(a\),使第\(i\)位加1后个位变成什么?

\(i=2\)时直接暴力处理,\(f[i]\)可以\(O(k)\)由\(f[i-1]\)推出来,复杂度\(O(n*k^3)\)。

有了f方便处理出\(g[i][p][x][a]\),\(i、p、a\)含义如上,x表示第i位要+x,

这里\(x=0\),g的值就是a,然后g自己推自己,复杂度\(O(n*k^3)\)。

接下来的部分就很傻逼了,带根联通块,直接在dfs序上dp,做到个位的时候,再跳跳看能不能跳到那个位去就好了。

Code:


#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std; const int N = 505; int n, k;
int d[N], x, y;
vector<int> e[N];
#define pb push_back
#define si size() int p[N], q[N], np[N], p0, fa[N]; void dg(int x) {
p[x] = ++ p0; np[p0] = x;
ff(j, 0, e[x].si) {
int y = e[x][j];
if(fa[x] != y) fa[y] = x, dg(y);
}
q[x] = p0;
} const int mo = 1e9 + 7; int f[N][10][10], g[N][10][10][10];
ll h[N][N][10][10]; void add(ll &x, ll y) {
(x += y) >= mo ? x -= mo : 0;
} int T; int main() {
// freopen("buried.in", "r", stdin);
// freopen("buried.out", "w", stdout);
k = 10;
for(scanf("%d", &T); T; T --) {
fo(i, 1, n) e[i].clear();
memset(h, 0, sizeof h);
fo(i, 1, n) fa[i] = 0; p0 = 0;
scanf("%d", &n);
fo(i, 1, n - 1) {
scanf("%d %d", &x, &y);
e[x].pb(y); e[y].pb(x);
}
fo(i, 1, n) scanf("%d", &d[i]);
fo(i, 1, n) sort(e[i].begin(), e[i].end());
dg(1);
//Initialization of F
ff(p, 0, k) {
ff(a, 0, k) if(p || a) {
int x = a;
while(x < k) {
x += max(x, p);
}
f[1][p][a] = x % k;
}
}
//dp F
fo(i, 2, n - 1) {
ff(p, 0, k) {
ff(a, 0, k) {
int x = a;
fo(c, 1, k) x = f[i - 1][max(p, c - 1)][x];
f[i][p][a] = x;
}
}
}
//dp g
fo(i, 2, n) {
ff(p, 0, k) {
ff(a, 0, k) {
g[i][p][0][a] = a;
ff(x, 1, k) g[i][p][x][a] = f[i - 1][max(x - 1, p)][g[i][p][x - 1][a]];
}
}
}
//dp h
ll ans = 0;
fo(j, 1, n) h[1][j][0][1] = 1;
fo(i, 1, n) {
int num = d[np[i]];
int ni = q[np[i]] + 1;
fo(j, 2, n) {
ff(p, 0, k) ff(a, 0, k) if(h[i][j][p][a] && (p || a)) {
add(h[i + 1][j - 1][max(p, num)][g[j][p][num][a]], h[i][j][p][a]);
add(h[ni][j][p][a], h[i][j][p][a]);
}
}
ff(p, 0, k) ff(a, 0, k) if(h[i][1][p][a] && (p || a)) {
int x = a;
while(x < num) x += max(x, p);
if(x == num) add(ans, h[i][1][p][a]);
add(h[ni][1][p][a], h[i][1][p][a]);
}
}
pp("%lld\n", ans);
}
}

最新文章

  1. Angular+Grunt+Bower+Karma+Protractor (Atom)
  2. Caffe 单独测试添加的layer
  3. 安装ANDROID5.0 ,adb连接不上
  4. python增删改查(四)
  5. 记录一次fat32格式U盘不识别问题
  6. Javascript入门学习
  7. static NSString *ID的改进
  8. JSON字符串与JSON对象的区别及转换
  9. 在VC6中使用ogre进行游戏开发
  10. Swift UI开发初探
  11. line-height的高度机理
  12. 业务开发(一)—— MySQL
  13. 洛谷P1007独木桥题解
  14. POJ 3107.Godfather 树形dp
  15. JS常见的小代码
  16. SQL 别名
  17. wamp支持win10吗?怎么设置?
  18. 要求根据RandomStr.java:使用类型转换生成六位验证字符串,示例程序每次运 行时,都会生成不同的字符串。
  19. Oracle 多表查询、查询运算符和集合运算
  20. Eclipse和Intel idea的常用技巧

热门文章

  1. xml json mongo
  2. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_04 IO字节流_13_使用字节流读取中文的问题
  3. Week6 - 676.Implement Magic Dictionary
  4. 每日js练习
  5. unity 编辑器教程
  6. Jmeter使用SSL(HTTPS协议)
  7. 15年6月8号 jsp内置对象总结
  8. linux下的dd命令使用详解
  9. 运维脚本-elasticsearch数据迁移python3脚本
  10. 深入ArrayList看fast-fail机制