LOADING

加载过慢请开启缓存,浏览器默认开启

daily 2

2023/4/21 daily

今天继续树形dp的旅程惹

CF 1691F

一上来就是重量级,我们首先确定怎么去数,我们可以遍历对应的节点,然后把树重构成以当前节点$u$为根的新树,然后根据对应的r是否是u或者不是u来进行状态区分,相应状态的解答写在注视里了

ll quick_pow(ll x,ll exp,int p)
{
      ll ans=1;
      while(exp)
      {
        if(exp&1)ans=ans*x%p;
        exp>>=1;
        x=x*x%p;
      }
      return ans;
}
ll inv[MAXN],fac[MAXN];
void init(int n,int p)
{
  memset(inv,0,sizeof(inv));
  memset(fac,0,sizeof(fac));
  inv[0]=fac[0]=1;
  for(int i=1;i<=n;++i)
  {
    fac[i]=fac[i-1]*i%p;
  }
  inv[n]=quick_pow(fac[n],p-2,p)%p;
  for(int i=n;i>=1;--i)inv[i-1]=inv[i]*i%p;
}
ll C(ll n,ll m,ll p)
{
  if(m>n||m<0)return 0;
  if(m==n)return 1;
  return fac[n]*inv[n-m]%p*inv[m]%p;
}
void solve(){
  int n,k;
  cin>>n>>k;
  vector<vector<int>>E(n+1);
  vector<int>fa(n+1);
  for(int i=1;i<=n-1;++i){
    int u,v;
    cin>>u>>v;
    E[u].push_back(v);
    E[v].push_back(u);
  }
  vector<int>size(n+1);
  function<void(int,int)>dfs=[&](int x,int f){
    fa[x]=f;
    size[x]=1;
    for(int v:E[x]){
      if(v!=f){
        dfs(v,x);
        size[x]+=size[v];
      }
    }
  };
  dfs(1,0);
  ll ans=0;
  for(int u=1;u<=n;++u){
    // r=u two situation that r in S or r not in S
    ll sum=0;
    for(int v:E[u]){
      int siz=v==fa[u]?n-size[u]:size[v];
      sum=sum+C(siz,k,MOD);
      sum%=MOD;
    }
    ans+=(C(n-1,k,MOD)-sum+C(n-1,k-1,MOD))*n;//two parts, first part is when r not in S,second is r in S
    ans%=MOD;
    // r!=u two situation that u in S or u not in S
    for(int r:E[u]){
      int cnt=r==fa[u]?n-size[u]:size[r];
      //u in S now the total size if n-cnt
      ans+=C(n-cnt-1,k-1,MOD)*cnt%MOD*(n-cnt)%MOD;//*cnt ,the size of subtree r is cnt
      ans%=MOD;
      //u not in S,choose the subtree which does not contain r and compute the value
      ans+=(C(n-cnt-1,k,MOD)-(sum-C(cnt,k,MOD))+MOD)%MOD*cnt%MOD*(n-cnt);
      ans%=MOD;
    }
  }
  cout<<(ans+MOD)%MOD<<'\n';
  return;
}

CF 1285D

trie树的dp,首先我们知道,如果trie树的两条边都可以走,那么这个位置给的返回值只能是1,然后直接板子套就好惹

void solve(){
  int n;
  cin>>n;
  vector tree(N<<2,vector<int>(2));
  vector<int>len(N<<2);
  int cnt=0;
  auto add=[&](int x){
    int u=0;
    for(int i=30;i>=0;--i){
        int bit=(x>>i)&1;
        if(!tree[u][bit]){
            tree[u][bit]=++cnt;
        }
        u=tree[u][bit];
        len[u]=i;
    }
  };
  for(int i=0;i<n;++i){
    int x;
    cin>>x;
    add(x);
  }
  function<ll(int)>dfs=[&](int u){
    ll sum=0;
    if(tree[u][0]&&tree[u][1])sum=(1<<len[tree[u][1]]);
    ll res=1e18;
    if(tree[u][0])res=min(res,dfs(tree[u][0]));
    if(tree[u][1])res=min(res,dfs(tree[u][1]));
    if(res==1e18)res=0;
    return sum+res;
  };
  cout<<dfs(0)<<'\n';
  return;
}