链接
D:
首先观察到颜色数等于树上点的种类数。找出最长链,设长度为D,那么至少有[(D+1)/2]种。
通过把所有点都补成对称形式,这个下界也是可以达到的。
下面考虑叶子个数。
若D为偶数,显然叶子的每一层度数最大的节点(度数-1)的乘积
若D为奇数,则可以枚举最长链增长1(唯一中心点 --> 两个中心点),叶子个数每种情况取min
注意代码细节,只能更专注的写才能不调试
#include
using namespace std;
#define maxn 120
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x) for(register int i = head[x] ; i ; i = e[i].next)
#define pb push_back
#define prev prev_
#define stack stack_
#define inf 0x3f3f3f3f
typedef unsigned long long ll;
struct node{
int next,to;
}e[maxn * 2];
int head[maxn],cnt;
int n,dth[maxn],fa[maxn],deg[maxn];
int mx[maxn];
int col;
ll num = 1e18,sum[maxn];
inline void adde(int x,int y){
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
void dfs(int x){
fore(i,x){
if ( e[i].to == fa[x] ) continue;
fa[e[i].to] = x , dth[e[i].to] = dth[x] + 1;
dfs(e[i].to);
}
}
void dfs(int x,int fa){
fore(i,x){
if ( e[i].to == fa ) continue;
dth[e[i].to] = dth[x] + 1;
dfs(e[i].to,x);
}
}
bool legal(int x,int fa){
return 1;
}
void init(){
dfs(1);
int rt = 0,x = 0;
rep(i,1,n) if ( dth[rt] < dth[i] ) rt = i;
rep(i,1,n) fa[i] = dth[i] = 0;
dth[rt] = 1 , dfs(rt);
rep(i,1,n) if ( dth[x] < dth[i] ) x = i;
col = (dth[x] + 1) / 2;
if ( dth[x] & 1 ){
rep(i,1,col - 1) x = fa[x];
dth[x] = 0 , dfs(x,0);
rep(i,1,n) mx[dth[i]] = max(mx[dth[i]],deg[i] - 1);
sum[col - 1] = 1;
repd(i,col - 2,1){
sum[i] = sum[i + 1] * mx[i];
}
num = sum[1] * deg[x];
fore(i,x){
if ( legal(e[i].to,x) ){
int mid1 = x , mid2 = e[i].to;
dth[mid1] = dth[mid2] = 0 , dfs(mid1,mid2) , dfs(mid2,mid1);
rep(j,0,n) sum[j] = 0 , mx[j] = 0;
rep(j,1,n) mx[dth[j]] = max(mx[dth[j]],deg[j] - 1);
sum[col - 1] = 1;
repd(j,col - 2,0){
sum[j] = sum[j + 1] * mx[j];
}
num = min(num,2ll * sum[0]);
}
}
}
else{
int mid1,mid2;
rep(i,1,col - 1) x = fa[x];
mid1 = x , mid2 = fa[x];
dth[mid1] = dth[mid2] = 0 , dfs(mid1,mid2) , dfs(mid2,mid1);
rep(i,1,n) mx[dth[i]] = max(mx[dth[i]],deg[i] - 1);
sum[col - 1] = 1;
repd(i,col - 2,0){
sum[i] = sum[i + 1] * mx[i];
}
num = 2ll * sum[0];
}
}
int main(){
freopen("input.txt","r",stdin);
scanf("%d",&n);
rep(i,1,n - 1){
int x,y;
scanf("%d %d",&x,&y);
adde(x,y) , adde(y,x);
deg[x]++ , deg[y]++;
}
init();
cout<
E:
首先观察一个结论:
因为字典序最大,所以插入的数字x >= y
若x==y,则可以在y后第一个x>r的地方插入,所得到序列完全相同。
因此,只考虑插入x > y的情况,就可以不重不漏的得到序列
把不断插入元素得到序列的过程看成在树上加入叶子得到一颗树的过程
每个节点维护两个值:id 插入顺序,val 填的元素
则该树满足
#include
using namespace std;
#define maxn 320
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x) for(register int i = head[x] ; i ; i = e[i].next)
#define pb push_back
#define prev prev_
#define stack stack_
#define inf 0x3f3f3f3f
typedef unsigned long long ll;
int n,k,mod;
ll f[maxn][maxn],sum[maxn][maxn];
ll c[maxn][maxn];
inline void up(ll &x,ll y) { x = (x + y) % mod; }
void init(){
c[0][0] = 1;
rep(i,1,n + 1){
c[i][0] = 1;
rep(j,1,i){
c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
}
}
}
int main(){
cin>>n>>k>>mod;
init();
repd(i,k,0) f[1][i] = 1 , sum[1][i] = (sum[1][i + 1] + f[1][i]) % mod;
rep(i,2,n + 1){
rep(j,0,k){
rep(l,1,i - 1){
up(f[i][j],c[i - 2][l - 1] * sum[l][j + 1] % mod * f[i - l][j] % mod);
}
}
repd(j,k,0) up(sum[i][j],sum[i][j + 1] + f[i][j]);
}
cout<