DFS and 记忆化搜索

CF1851E Nastya and Potions - 洛谷

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int N = 2e5 + 7;
#define vi vector<int>
int c[N]; 
int sz[N];
vi t[N];  
int dfs(int u) {
    if (sz[u] != -1) return sz[u]; //剪枝
    int ans = 0;//另开一个数记录子节点之和
    for (int v : t[u])        
        ans += dfs(v);
    return sz[u] = min(ans, c[u]);
}
void solve() {
    int n, k, m; cin >> n >> k;
    for (int i = 1; i <= n; ++i) {
        cin >> c[i];    
        sz[i] = -1;       
        t[i].clear();    
    }
    for (int i = 1; i <= k; ++i) {
        int p; cin >> p;
        c[p] = 0; 
        sz[p] = 0; 
    }
    for (int i = 1; i <= n; ++i) {
        cin >> m;
        for (int j = 1; j <= m; ++j) {
            int v; cin >> v;
            if (c[i] == 0) continue;
            t[i].push_back(v);
        }
        if(!m)sz[i] = c[i];
    }
    for (int i = 1; i <= n; ++i) 
        cout << dfs(i) << " \n"[i == n];
}
signed main() {
    ios :: sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while (T--) solve();
    return 0;
}

[数的划分 - 洛谷](https://www.luogu.com.cn/problem/P1025

递归 + 剪枝

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
int n, k;
int ans;
void dfs(int s, int cnt, int last){
 if(s == n && cnt == k){
  ++ans; return ;
 }
if(s >= n || cnt >= k)return ;//剪枝
 for(int i = last; i <= n - s; ++i)//n - s相当于剪枝了// last 避免重复计数
  dfs(s + i, cnt + 1, i);
}
void solve(){
  cin >> n >> k;
dfs(0, 0, 1);
cout << ans << endl;
}
signed main(){
  ios :: sync_with_stdio(0), cin.tie(0), cout.tie(0);
  int T = 1;
  //cin >> T;
  while(T--)solve();
  return 0;
}

P9425 [蓝桥杯 2023 国 B] AB 路线 - 洛谷

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define vi vector<int>
#define vii vector<vi>
#define pii pair<int, int>
const int mod = 1e9 + 7;
const int N = 1e3 + 5;
int n, m, k, ans = -1;
char s[N][N];
int dp[N][N][11][2];//(i, j), k, A0,B1
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
struct node{
  int x, y;
  int cnt;
  int stp;
  char ch;
};
void  bfs(){
  queue<node>q;
  q.push({1, 1, 1, 0, s[1][1]});
  while(!q.empty()){
    //auto [x, y, cnt, stp, ch] = q.front(); q.pop();
    node t = q.front(); q.pop();
    if(t.x == n && t.y == m){
      ans = t.stp;
      return ;
    }
    for(int i = 0; i < 4; ++i){
        int nx = t.x + dx[i];
        int ny = t.y + dy[i];
        if(nx < 1 || nx > n || ny < 1 || ny > m)continue;
        if(t.ch == s[nx][ny] && t.cnt < k){//相同字符可以走的条件
            if(!dp[nx][ny][t.cnt + 1][s[nx][ny] - 'A']){
              dp[nx][ny][t.cnt + 1][s[nx][ny] - 'A'] = 1;
              q.push({nx, ny, t.cnt + 1, t.stp + 1, s[nx][ny]});
            }
        }
        else if(t.ch != s[nx][ny] && t.cnt == k){//不同字符可以走的条件
              if(!dp[nx][ny][1][s[nx][ny] - 'A']){
              dp[nx][ny][1][s[nx][ny] - 'A'] = 1;
              q.push({nx, ny, 1, t.stp + 1, s[nx][ny]});
        }
      }
    }
  }
}
void solve(){
  cin >> n >> m >> k;
  for(int i = 1; i <= n; ++i)
    for(int j = 1; j <= m; ++j)cin >> s[i][j];
  memset(dp, 0, sizeof dp);
  dp[1][1][1][0] = 0;
  bfs();
    cout << ans << endl;
}
signed main(){
  ios :: sync_with_stdio(0), cin.tie(0), cout.tie(0);
  int T = 1;
  //cin >> T;
  while(T--)solve();
  return 0;
}

P1486 - 走格子 Ⅲ - ZJHUOJ

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define vi vector<int>
#define vii vector<vi>
#define pii pair<int, int>
const int mod = 1e9 + 7;
const int N = 1e3 + 5;
int n, m;
int dp[N][N][4][3];//(i, j)点的方向以及方向的次数
int dfs(int x, int y, int d, int c){//0起点, 1右, 2下, 3上
  if(x == n && y == m)return 1;
  if(dp[x][y][d][c] != -1)return dp[x][y][d][c];
  int res = 0;
  if(c == 2){ //等于2只有一种情况
      if (d == 1) {//右 
          if(x + 1 <= n) res = (res + dfs(x + 1, y, 2, 1)) % mod;//下
          if(x - 1 >= 1) res = (res + dfs(x - 1, y, 3, 1)) % mod;//上
      } 
      else{//上/下
          if(y + 1 <= m) res = (res + dfs(x, y + 1, 1, 1)) % mod;//向右
    }
  }
  else {
    if(d == 0){
    if(y + 1 <= m)res = (res + dfs(x, y + 1, 1, 1)) % mod;//向右
    if(x + 1 <= n)res = (res + dfs(x + 1, y, 2, 1)) % mod;//向下
  }
  else if(d == 1){//向右
    if(y + 1 <= m)res = (res + dfs(x, y + 1, 1, c + 1)) % mod;//向右
    if(x + 1 <= n)res = (res + dfs(x + 1, y, 2, 1)) % mod;//向下
    if(x - 1 >= 1) res = (res + dfs(x - 1, y, 3, 1)) % mod;//向上
  }
  else if(d == 2){//向下
    if(x + 1 <= n)res = (res + dfs(x + 1, y, 2, c + 1)) % mod;//向下
    if(y + 1 <= m)res = (res + dfs(x, y + 1, 1, 1)) % mod;//向右
  }
  else {//向上
    if(x - 1 >= 1)res = (res + dfs(x - 1, y, 3, c + 1)) % mod;//向上
    if(y + 1 <= m)res = (res + dfs(x, y + 1, 1, 1)) % mod;//向右
  }
}
  dp[x][y][d][c] = res;//记忆
  return res;
}
void solve(){
  cin >> n >> m;
  memset(dp, -1, sizeof dp);
  cout << dfs(1, 1, 0, 0) % mod << endl;
}
signed main(){
  ios :: sync_with_stdio(0), cin.tie(0), cout.tie(0);
  int T = 1;
  //cin >> T;
  while(T--)solve();
  return 0;
}
优化版代码:
// dp[i, j]定义:从上往下或从下往上到达(i,j)位置的路径数
// 状态转移方程:dp[i, j] = dp[i ± 1, j - 1] + dp[i ± 2,j-2]
#include<bits/stdc++.h>
using namespace std;
const int mxn = 1e3+5, MOD = 1e9+7;
int n, m, dp[mxn][mxn];
void f(int x, int y){
    for(int i = -2; i <= 2; ++i)
        for(int j = 1; i && j <= 2; ++j)
            dp[x][y] = (dp[x][y] + dp[x+i][y-j])%MOD;
}
int main(){
    scanf("%d%d", &n, &m);
    n += 1, m += 1;
    for(int i = 2; i <= min(n, 4); ++i) dp[i][2] = 1;
    for(int j = 3; j <= m; ++j) // 必须按列更新
        for(int i = 2; i <= n; ++i) f(i,j);
    // print();
    printf("%d\n", ((dp[n][m]+dp[n][m-1])%MOD+dp[n][m-2])%MOD);
    return 0;
}

归并排序(并找逆序): 归并排序使用分治策略,将数组递归地一分为二,直到每个子数组只包含一个元素。
map<string,int>mp
map在迭代器中才可以用first,second
不然就用mp[i]=s;
map的直接赋值法{
m1["def"] = 2;||
m2.insert({ "abc", 1 });
}
归并排列过程示例

![[Pasted image 20250411200333.png]]

从上往下递归,从下往上分解
类似dfs的树,and每归并一层都会更新当前排序,然后被上一层作为排序的依据

归并排序

![[Pasted image 20250411202802.png

P5149 会议座位 - 洛谷

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
//#define int long long
#define ll long long
const int mxn=1e5+7;
int a[mxn],n,b[mxn];//b辅助(临时)数组
ll ans;
string s;
map<string,int>mp;//分治、归并排序
void merge(int l,int r){
     if(r<=l)return;
     int mid=l+(r-l>>1);//1LL
     merge(l,mid); merge(mid+1,r);
     int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r){//先赋值再++
      if(a[i]<a[j])b[k++]=a[i++];//左右两边较小的排在前面
      else b[k++]=a[j++],ans+=mid-i+1;//要比较的两个子序列都已经排好序//在子序列的每个子序列合并时也已经找好逆序数
    }
    while(i<=mid)b[k++]=a[i++];
    while(j<=r)b[k++]=a[j++];//左右两边剩余没排完的排上去
    for(int i=l;i<=r;++i)a[i]=b[i];//更新原数组的排序
    return;
}
void solve(){
  cin>>n;
  for(int i=1;i<=n;++i){
    cin>>s;
    mp[s]=i;
 // mp.insert({s,i});
  }
  for(int i=1;i<=n;++i){
    cin>>s;
    a[mp[s]]=i;
  }
  merge(1,n);
  cout<<ans<<endl;
  return ;
}
signed main(){
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
   int T=1;
  //cin>>T;
  while(T--)solve();
  return 0;
}
相信奇迹的人,本身就和奇迹一样了不起。——笛亚 《星游记》
next_permutation()用法
时间复杂度是O(n!)注意剪枝
#include<bits/stdc++.h>
using namespace std;
signed main(){
  int n,a[10]={1,2,3,4,5};
  do{
   for(int i=0;i<=4;++i)cout<<a[i];
   cout<<endl;
  }while(next_permutation(a,a+5));//最好用一个数组来存数
  return 0;
}
注:next_permutation()函数从当前的全排列开始,逐个输出更大的去安排列,而不是输出所有的全排列
如果想要得到全排列可以先用sort排序

要对杨辉三角数敏感

杨辉三角代码

(now number=同列上一层的前两个数字相加)

c[1][1]=1;//最左上角的数初始化为1 
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];//每个数都等于它肩上两数之和
法二
//下面构造杨辉三角(即组合数表)
pc[0]=pc[n-1]=1; //从0开始,杨辉三角性质,两边都是1 
if (n>1)for(int i=1;i*2<n;i++)
pc[i]=pc[n-1-i]=(n-i)*pc[i-1]/i; //利用杨辉三角对称性和组合数公式计算

P1118 Backward Digit Sums G/S - 洛谷

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
//#define int long long
//#define ll long long
//#define Ll unsigned long long
//const int mxn=3e5+7;
//string s;
int n,m,t,a[20],b[20][20];
void solve(){
  cin>>n>>m;
  a[1]=1, b[1][1]=1;//最后一行各系数恰好是杨辉三角数!
 for(int i=2;i<=n;++i){//第i层,杨辉三角是从1开始的
  a[i]=i;
 for(int j=1;j<=i;++j)b[i][j]=b[i-1][j]+b[i-1][j-1];}
 do{
  t=0;
  for(int i=1;i<=n;++i){
     t+=a[i]*b[n][i];
    if(t>m)break;
  }
  if(t==m){
    for(int i=1;i<=n;++i)cout<<a[i]<<(i==n?"\n":" ");
    break;
    }
 }while(next_permutation(a+1,a+1+n));
  return ;
}
signed main(){
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
   int T=1;
  //cin>>T;
  while(T--)solve();
  return 0;
}
代码2
int n,m,a[20],b[20][20],vis[20];
void dfs(int k,int t){//t要放在这里,不然会一直被加
  if(t>m)return;
  if(k==n+1&&t==m){
    for(int i=1;i<=n;++i)cout<<a[i]<<(i==n?"\n":" ");
   exit(0) ;//正常运行并退出程序
  }
   if(k==n+1)return;
  for(int i=1;i<=n;++i){
    if(!vis[i]){
       vis[i]=1;//在for循环里标记!
      a[k]=i;
       dfs(k+1,t+i*b[n][k]);
     vis[i]=0;//每次dfs完赶紧复位!return后把vis变成0供下一次根节点搜索的使用
      }
  }
}
void solve(){
  cin>>n>>m;
  b[1][1]=1;
  for(int i=2;i<=n;++i)
    for(int j=1;j<=i;++j)
    b[i][j]=b[i-1][j-1]+b[i-1][j];
  dfs(1,0);
  return ;
}

方格取数 - 洛谷

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
//#define int long long
//#define ll long long
//vector<pair<int,int>>E[mxn];
//double ans=DBL_MAX;//double的最大值
//vector<vector<int>>e(mxn);
//typedef pair<int, int>PII;
const int mxn=20;
int dp[mxn][mxn][mxn],a[mxn][mxn],w[mxn][mxn],n,m,ans;
// int read(){
//   int x=0; bool t=false; char ch=getchar();
//   while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
//   if(ch=='-')t=true, ch=getchar();
//   while(ch<='9'&&ch>'0')x=x*10+ch-48,ch=getchar();
//   return t? -x:x; 
// }//快读
void solve(){
cin>>n;
int a,b,c;
while(cin>>a>>b>>c,a|b|c){
  w[a][b]=c;
 // cout<<w[a][b]<<endl;
}
int x2,y2;
for(int k=2;k<=2*n;++k){//k<=2*n是因为省略了纵坐标循环,实际上至少走2*(n-1)步才能到达
for(int x1=1;x1<=n;++x1){
    for(int x2=1;x2<=n;++x2){
      int y1=k-x1,y2=k-x2;
      int t=w[x1][y1];
      if(x1!=x2)t+=w[x2][y2];
      int &x=dp[k][x1][x2];
      x=max(x,dp[k-1][x1-1][x2]+t);
      x=max(x,dp[k-1][x1-1][x2-1]+t);//dd x是由上一步继承来的,y是现在的位置,则表示的位移是dd
      x=max(x,dp[k-1][x1][x2-1]+t);
      x=max(x,dp[k-1][x1][x2]+t);//rr
      //在x1,x2的移动一步中选择最大的那个,这一步状态是由上一步得来的
    }
   }
  }
  cout<<dp[2*n][n][n]<<endl;
}
signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int T = 1;
	//cin >> T;
	while (T--)solve();
	return 0;
}

C - Concat (X-th)

dfs+排序

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
#define vi vector<int>
#define vii vector<vi>
const int N = 1e6 + 10;
string res[N], s[N];
int tot, n, k, x;
void dfs(int dep, string t){
    if(dep > k){res[++tot] = t; return;}
    for(int i = 1; i <= n; ++i)dfs(dep + 1, t + s[i]);//这样的dfs可以遍历所有
}
void solve(){
    cin >> n >> k >> x;
    for(int i = 1; i <= n; ++i)cin >> s[i];
    dfs(1, "");
    sort(res + 1, res + 1 + tot);
    cout << res[x] << endl;
}
signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
   // cin >> T; 
    while(T --)solve();
    return 0;
}

D - Goin' to the Zoo

DFS

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define pii pair<int, int>
#define vi vector<int>
#define vii vector<vi>
#define lowbit(x) (x & (-x))
const int N = 1e2 + 7;
int n, m;
int w[15], k[N], a[N][N];
int v[N];//每个动物园看了几次
int ans = 1e18;
void dfs(int t, int sm){
    //正在枚举第t个动物园的情况,已经花了sm元
    if(t == n + 1){
        for(int i = 1; i <= m; ++i){
            //计算第i个动物看了几次;
            int tmp = 0;
            for(int j = 1; j <= k[i]; ++j)
                tmp += v[a[i][j]];
            if(tmp < 2)return ;
        }
        ans = min(ans, sm);
        return ;
    }
    for(int x = 0; x <= 2; ++x){
        v[t] = x;
        dfs(t + 1, sm + x * w[t]);
        //对于每个园的x = 0, 1, 2次的每种情况继续往下遍历
    }  
}
void solve(){
   cin >> n >> m;
   for(int i = 1; i <= n; ++i)cin >> w[i];
   for(int i = 1; i <= m; ++i){
    cin >> k[i];
    for(int j = 1; j <= k[i]; ++j)
        cin >> a[i][j];//第i个动物出现在第j个园的号
   }
   dfs(1, 0);
   cout << ans << endl;
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
    //cin >> T;
    while(T--) solve();
    return 0;
}

D - 2x2 Erasing 2

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long  
#define vi vector<int>
#define vii vector<vi>
const int inf = 0x3f3f3f3f;
const int N = 10;
int cnt = 0, n, m, ans = inf;
  char s[N][N];//在算法竞赛中,对于网格类问题通常推荐使用char数组而不是string数组
 void dfs(int x, int y, int cnt){
  if(cnt >= ans)return;
  if(y == m)dfs(x + 1, 1, cnt);
  if(x == n){ans = min(ans, cnt); return;}
  if(s[x][y] == '.' || s[x][y + 1] == '.' || s[x + 1][y] == '.' || s[x + 1][y + 1] == '.')dfs(x, y + 1, cnt);
  else {
    s[x + 1][y + 1] = '.';
    dfs(x, y + 1, cnt + 1);//修改后继续遍历下一个数
    s[x + 1][y + 1] = '#';

    s[x + 1][y] = '.';
    dfs(x, y + 1, cnt + 1);
    s[x + 1][y] = '#';
  }
 }
void solve() { 
 cin >> n >> m;
 ans = inf;
 for(int i = 1; i <= n; ++i)
  for(int j = 1; j <= m; ++j)cin >> s[i][j];
   for(int i = 1; i <= n; ++i){

  for(int j = 1; j <= m; ++j)cout << s[i][j];
  cout << endl;
   }
  dfs(1, 1, 0);
  cout << ans << endl;
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while(T--) solve();
    return 0;
}

AT Replace

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
const int N = 3e1 + 5;
#define vi vector<int>
#define vii vector<vi>
#define pii pair<int, int>
int n, to[N], ans;
bool vis[N];//标记可达字母
void dfs(int x){
  if(vis[x])return ;
  vis[x] = 1;
  if(to[x] != -1)dfs(to[x]);
}
void solve(){
 cin >> n;
 string s, t; cin >> s >> t;
 memset(to, -1, sizeof to);
 vi in(N); bool f = 0;
 for(int i = 0; i < n; ++ i){
  int x = s[i] - 'a';
  int y = t[i] - 'a';
  if(to[x] != -1 && to[x] != y){cout << "-1\n"; return ;}//出现了一个字母指向两个字母
  to[x] = y;
 }
 for(int i = 0; i < 26; ++ i){
  if(to[i] != -1){
    ans += (to[i] != i);//如果指向其他字母
    ++in[to[i]];
  }
 }
 for(int i = 0; i < 26; ++i)
  if(in[i] == 0 || to[i] == -1)f = 1;//查找空闲字母
 for(int i = 0; i < 26; ++i)
  if(in[i] == 0 || to[i] == i)dfs(i);//处理链(或点)和自环
  for(int i = 0; i < 26; ++i){//剩余的是环
    if(!vis[i]){
      if(!f){cout << "-1\n"; return ;}
      ++ans;//只加1是因为前面环中各个节点已经统计过了
      dfs(i);
    }
  }
  cout << ans << endl;
}
signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T--) solve();
    return 0;
}

D - Skibidi Table

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long  
#define vi vector<int>
#define vii vector<vi>
#define pii pair<int, int>
inline int cu(int x, int n){//一定要从大到小
  if(x == 0)return (1ll << (n - 1));//一次移动坐标增减的情况
  if(x == 1)return ((1ll << (2 * n - 2)) * 3);//右上   //先移位再乘
  if(x == 2)return ((1ll << (2 * n - 2)) * 2);//左下
  if(x == 3)return (1ll << (2 * n - 2));//右下
}
inline int get1(int x, int y, int n){//根据坐标查值 //x,y每次移动对应的值的变化是不同的
  if(n == 0)return 1;
  if(x > cu(0, n)){//x和y都能减的情况是左下!!
    if(y > cu(0, n))return cu(3, n) + get1(x - cu(0, n), y - cu(0, n), n - 1);
    else return cu(2, n) + get1(x - cu(0, n), y, n - 1);
  }
  else if(y > cu(0, n))return cu(1, n) + get1(x, y - cu(0, n), n - 1);
  else return get1(x, y, n - 1);
}
inline pii get2(int d, int n){//根据值查坐标
    if(n == 0)return {1, 1};
    if(d > cu(1, n)){
      auto [x,y] = get2(d - cu(1, n), n-1);
	    return {x, y + cu(0, n)};
    }
    else if(d > cu(2, n)){
      auto [x,y] = get2(d - cu(2, n), n-1);
	    return {x + cu(0, n), y};
    }
    else if(d > cu(3, n)){
      auto [x,y] = get2(d - cu(3, n), n-1);
	    return {x + cu(0, n), y + cu(0, n)};
    }
    else return get2(d, n-1);
}
void solve() {
  int n, q; cin >> n >> q; 
  string s; int x, y, d;
  while(q--){
    cin >> s;
    if(s == "->"){
      cin >> x >> y;
      cout << get1(x, y, n) << endl;
    }
    else {
      cin >> d;//!!
      auto [x0, y0] = get2(d, n);
      cout << x0 << " " << y0 << endl;
    }
  }
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while(T--) solve();
    return 0;
}

左儿子右兄弟 - Problem - QOJ.ac

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define vi vector<int>
const int N = 1e5 + 7, mod = 998244353;
vi son[N];
int fac[N], sz[N];
int n;
void dfs(int u){
  sz[u] = 1;
  for(auto v : son[u]){
    dfs(v);
    sz[u] += sz[v];//先递归子节点再累加
  }
}
void solve(){
 cin >> n;  fac[0] = 1;
 for(int i = 1; i <= n; ++i)fac[i] = i * fac[i - 1] % mod;
 for(int fa, i = 2; i <= n; ++i) {
  cin >> fa;
  son[fa].push_back(i);
 }
 dfs(1);
 int sum = 0, res = 1;
 for(int i = 1; i <= n; ++i){
  if(son[i].empty())continue;
    sort(son[i].begin(), son[i].end(), [&](int x, int y){
      return sz[x] > sz[y];
    });
    int k = son[i].size();
    for(int j = 0; j < k; ++j)
      sum += (j + 1) * sz[son[i][j]];//贡献,被加了几次
    int lsz = sz[son[i][0]];
    vi cnt; int count = 1;
    for(int j = 1; j < k; ++j){
      if(sz[son[i][j]] == lsz) ++count; //有相同的子树可以全排列
      else {
        cnt.push_back(count);
        lsz = sz[son[i][j]];
        count = 1;
      }
    }
    cnt.push_back(count);
    for(auto c: cnt) res = res * fac[c] % mod;
 }
 sum += n;
 cout << sum << endl << res << endl;
}
signed main(){
  ios :: sync_with_stdio(0),cin.tie(0), cout.tie(0);
  int T = 1; 
 // cin >> T;
  while(T--) solve();
  return 0;
}
posted @ 2025-11-06 13:06  Glosie  阅读(5)  评论(0)    收藏  举报