AtCoder Beginner Contest 160 出場者の 数は9747人 です。コンテスト開始から3分後にすべての質問をご覧ください
AtCoder Beginner Contest 160 F Distributing Integers change root dp +順列と組み合わせ
一般的なカタログについては、https://blog.csdn.net/mrcrack/article/details/104454762を参照してください
オンライン評価用アドレスhttps://atcoder.jp/contests/abc160/tasks/abc160_f
ルートdpを変更する理解できない場合は、この記事を読むことができます[codeforces 1187E]ツリーペインティングルートdpを変更する
階乗逆元を計算できない場合は、このペーパーで階乗逆元の3つの高速な方法を確認できます。
1.次の図では、ルートノードとして3を使用しています。これは、カテゴリ数の計算の元です840
1.1は次のとおりです。計算はリーフノードから開始する必要があり、組み合わせ数学の乗算原理を使用します。1このデータはルートノードによって占められていることに注意してください3
1.2ノード3とノード6が統合され、ノード6に割り当てられたノード6、7、8グループに割り当てられた、ノード3によって占有されたデータ1と残りのデータ5を差し引いて、合計6つのデータが利用可能になります。
1.3ノード3とノード2が統合され、合計8つのデータが利用可能になります。ノード3によって占有されているデータ1を差し引いた後、ノード1、2グループに割り当てられている7つのデータが残り、C(7、2)になります。
2.サンプル4を例にして、データ総当たりの生成プロセスを示します。データ生成プロセスが不明な場合は、ACコードのdfs1パーツの内容を確認できます。
2.1 1をルートとして、対応するデータ生成プロセスは次のとおりです。
[U] = [I] *は[U] * C([IN] -1、S [i]のOT)に、
pre [u]はuをルートとするサブツリーの配置の数、sz [u]はuをルートとするサブツリーのノードの数
sz[8]=1 pre[8]=1 sz[6]=2 pre[6]=1
sz[7]=1 pre[7]=1 sz[6]=3 pre[6]=2
sz[6]=3 pre[6]=2 sz[3]=4 pre[3]=2
sz[5]=1 pre[5]=1 sz[3]=5 pre[3]=8
sz[4]=1 pre[4]=1 sz[3]=6 pre[3]=40
sz[3]=6 pre[3]=40 sz[2]=7 pre[2]=40
sz[2]=7 pre[2]=40 sz[1]=8 pre[1]=40
sz[1]=8
sz[2]=7
sz[3]=6
sz[4]=1
sz[5]=1
sz[6]=3
sz[7]=1
sz[8]=1
pre[1]=40
pre[2]=40
pre[3]=40
pre[4]=1
pre[5]=1
pre[6]=2
pre[7]=1
pre[8]=1
2.2 2をルートとして、対応するデータ生成プロセスは次のとおりです。
sz[8]=1 pre[8]=1 sz[6]=2 pre[6]=1
sz[7]=1 pre[7]=1 sz[6]=3 pre[6]=2
sz[6]=3 pre[6]=2 sz[3]=4 pre[3]=2
sz[5]=1 pre[5]=1 sz[3]=5 pre[3]=8
sz[4]=1 pre[4]=1 sz[3]=6 pre[3]=40
sz[3]=6 pre[3]=40 sz[2]=7 pre[2]=40
sz[1]=1 pre[1]=1 sz[2]=8 pre[2]=280
sz[1]=1
sz[2]=8
sz[3]=6
sz[4]=1
sz[5]=1
sz[6]=3
sz[7]=1
sz[8]=1
pre[1]=1
pre[2]=280
pre[3]=40
pre[4]=1
pre[5]=1
pre[6]=2
pre[7]=1
pre[8]=1
2.3 3をルートとして使用すると、対応するデータ生成プロセスは次のようになります。
sz[8]=1 pre[8]=1 sz[6]=2 pre[6]=1
sz[7]=1 pre[7]=1 sz[6]=3 pre[6]=2
sz[6]=3 pre[6]=2 sz[3]=4 pre[3]=2
sz[5]=1 pre[5]=1 sz[3]=5 pre[3]=8
sz[4]=1 pre[4]=1 sz[3]=6 pre[3]=40
sz[1]=1 pre[1]=1 sz[2]=2 pre[2]=1
sz[2]=2 pre[2]=1 sz[3]=8 pre[3]=840
sz[1]=1
sz[2]=2
sz[3]=8
sz[4]=1
sz[5]=1
sz[6]=3
sz[7]=1
sz[8]=1
pre[1]=1
pre[2]=1
pre[3]=840
pre[4]=1
pre[5]=1
pre[6]=2
pre[7]=1
pre[8]=1
2.4 4をルートとして、対応するデータ生成プロセスは次のとおりです。
sz[8]=1 pre[8]=1 sz[6]=2 pre[6]=1
sz[7]=1 pre[7]=1 sz[6]=3 pre[6]=2
sz[6]=3 pre[6]=2 sz[3]=4 pre[3]=2
sz[5]=1 pre[5]=1 sz[3]=5 pre[3]=8
sz[1]=1 pre[1]=1 sz[2]=2 pre[2]=1
sz[2]=2 pre[2]=1 sz[3]=7 pre[3]=120
sz[3]=7 pre[3]=120 sz[4]=8 pre[4]=120
sz[1]=1
sz[2]=2
sz[3]=7
sz[4]=8
sz[5]=1
sz[6]=3
sz[7]=1
sz[8]=1
pre[1]=1
pre[2]=1
pre[3]=120
pre[4]=120
pre[5]=1
pre[6]=2
pre[7]=1
pre[8]=1
2.5は5をルートとし、対応するデータ生成プロセスは次のとおりです。
sz[8]=1 pre[8]=1 sz[6]=2 pre[6]=1
sz[7]=1 pre[7]=1 sz[6]=3 pre[6]=2
sz[6]=3 pre[6]=2 sz[3]=4 pre[3]=2
sz[4]=1 pre[4]=1 sz[3]=5 pre[3]=8
sz[1]=1 pre[1]=1 sz[2]=2 pre[2]=1
sz[2]=2 pre[2]=1 sz[3]=7 pre[3]=120
sz[3]=7 pre[3]=120 sz[5]=8 pre[5]=120
sz[1]=1
sz[2]=2
sz[3]=7
sz[4]=1
sz[5]=8
sz[6]=3
sz[7]=1
sz[8]=1
pre[1]=1
pre[2]=1
pre[3]=120
pre[4]=1
pre[5]=120
pre[6]=2
pre[7]=1
pre[8]=1
2.6はルートとして6を取り、対応するデータ生成プロセスは次のとおりです。
sz[8]=1 pre[8]=1 sz[6]=2 pre[6]=1
sz[7]=1 pre[7]=1 sz[6]=3 pre[6]=2
sz[5]=1 pre[5]=1 sz[3]=2 pre[3]=1
sz[4]=1 pre[4]=1 sz[3]=3 pre[3]=2
sz[1]=1 pre[1]=1 sz[2]=2 pre[2]=1
sz[2]=2 pre[2]=1 sz[3]=5 pre[3]=12
sz[3]=5 pre[3]=12 sz[6]=8 pre[6]=504
sz[1]=1
sz[2]=2
sz[3]=5
sz[4]=1
sz[5]=1
sz[6]=8
sz[7]=1
sz[8]=1
pre[1]=1
pre[2]=1
pre[3]=12
pre[4]=1
pre[5]=1
pre[6]=504
pre[7]=1
pre[8]=1
2.7はルートとして7を取り、対応するデータ生成プロセスは次のとおりです
sz[8]=1 pre[8]=1 sz[6]=2 pre[6]=1
sz[5]=1 pre[5]=1 sz[3]=2 pre[3]=1
sz[4]=1 pre[4]=1 sz[3]=3 pre[3]=2
sz[1]=1 pre[1]=1 sz[2]=2 pre[2]=1
sz[2]=2 pre[2]=1 sz[3]=5 pre[3]=12
sz[3]=5 pre[3]=12 sz[6]=7 pre[6]=72
sz[6]=7 pre[6]=72 sz[7]=8 pre[7]=72
sz[1]=1
sz[2]=2
sz[3]=5
sz[4]=1
sz[5]=1
sz[6]=7
sz[7]=8
sz[8]=1
pre[1]=1
pre[2]=1
pre[3]=12
pre[4]=1
pre[5]=1
pre[6]=72
pre[7]=72
pre[8]=1
2.8は8をルートとし、対応するデータ生成プロセスは次のとおりです。
sz[7]=1 pre[7]=1 sz[6]=2 pre[6]=1
sz[5]=1 pre[5]=1 sz[3]=2 pre[3]=1
sz[4]=1 pre[4]=1 sz[3]=3 pre[3]=2
sz[1]=1 pre[1]=1 sz[2]=2 pre[2]=1
sz[2]=2 pre[2]=1 sz[3]=5 pre[3]=12
sz[3]=5 pre[3]=12 sz[6]=7 pre[6]=72
sz[6]=7 pre[6]=72 sz[8]=8 pre[8]=72
sz[1]=1
sz[2]=2
sz[3]=5
sz[4]=1
sz[5]=1
sz[6]=7
sz[7]=1
sz[8]=8
pre[1]=1
pre[2]=1
pre[3]=12
pre[4]=1
pre[5]=1
pre[6]=72
pre[7]=1
pre[8]=72
3.ルートdp生成用のデータを生成するプロセスを示す例としてサンプル4を取り上げます
3.1 1をルートとして使用すると、対応するデータ生成プロセスは次のようになります。
pre [u]はuをルートとするサブツリーの配置の数、sz [u]はuをルートとするサブツリーのノードの数
sz[8]=1 pre[8]=1 sz[6]=2 pre[6]=1
sz[7]=1 pre[7]=1 sz[6]=3 pre[6]=2
sz[6]=3 pre[6]=2 sz[3]=4 pre[3]=2
sz[5]=1 pre[5]=1 sz[3]=5 pre[3]=8
sz[4]=1 pre[4]=1 sz[3]=6 pre[3]=40
sz[3]=6 pre[3]=40 sz[2]=7 pre[2]=40
sz[2]=7 pre[2]=40 sz[1]=8 pre[1]=40
sz[1]=8
sz[2]=7
sz[3]=6
sz[4]=1
sz[5]=1
sz[6]=3
sz[7]=1
sz[8]=1
pre[1]=40
pre[2]=40
pre[3]=40
pre[4]=1
pre[5]=1
pre[6]=2
pre[7]=1
pre[8]=1
vは次の検索のルート、uは現在のルート、tp [v]はvをルートとする場合のpre [u]の値を表します。
tp [v] = ans [u] / pre [v] / C(n-1、sz [v]);
ans [u] = tp [v] * pre [u] * C(n-1、n-sz [u]);
ans[1]=40 u=2 fa=1
tp[2]=ans[1]/pre[2]/C(n-1,sz[1])=40/40/C(7,7)=1
ans[2]=tp[2]*pre[2]*C(n-1,n-sz[2])=1*40*C(7,1)=280
ans[2]=280 u=3 fa=2
tp[3]=ans[2]/pre[3]/C(n-1,sz[2])=280/40/C(7,6)=1
ans[3]=tp[3]*pre[3]*C(n-1,n-sz[3])=1*40*C(7,2)=840
u=6 fa=3
u=8 fa=6
u=7 fa=6
u=5 fa=3
u=4 fa=3
40
280
840
120
120
504
72
72
アイデアはhttps://www.cnblogs.com/JohnRan/p/12591555.htmlと同じです
F. n個のノードのツリーを与え、1-nを順番に配置し、この側の別の点が既に数値を配置しているという条件を配置します。ノード1-nに1を配置する解の数を見つけます。
ノード1-nに1を置くためのソリューションの数が必要なため、ルートdpが明示的に示されています(他の方法があるかもしれませんが、私はちょっとしません。最初に、ノード1に1を置くときのオペランドのカウント方法を検討します。 。
pre [v]をvをルートとするサブツリーの配置数とする。今回は単純な乗算の原則です。最初に選択し、次にサブツリー配置に入れます。初めてdfsがすべてのpre []を処理できるようになります。根を変えるとき
まずuの息子vがルートである場合、最初にuをvサブツリーのpre [u]として取得する必要があることを考慮する必要があります。明らかに(紙に少し書く必要があるかもしれませんが、原則は選択してから配置することです)ans [u] /(pre [v] * C(n-1、sz [v])) [v]しかし、あなたのためだけに
このサブツリーはいくつかの数値を再び選択します。これは明らかにC(n-1、n-sz [v])です。uの回答の計算方法によれば、vに直接適用できます。詳細はコードを参照してください。
ACコードは以下の通りです
#include <cstdio>
#include <algorithm>
#define LL long long
#define mod 1000000007
#define maxn 200010
using namespace std;
LL fact[maxn],inv[maxn];
int n,head[maxn],cnt,sz[maxn];//sz[u]是以u为根的子树的节点数
LL pre[maxn],ans[maxn],tp[maxn];//pre[u]是以u为根的子树的安排方式数
struct node{
int to,next;
}e[maxn<<1];
void add_edge(int u,int v){//邻接表
cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
LL quick_pow(LL a,LL b){//快速幂
LL ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init(){
int i,u,v;
scanf("%d",&n);
for(i=1;i<n;i++){
scanf("%d%d",&u,&v);
add_edge(u,v),add_edge(v,u);//无向图
}
fact[0]=1;
for(i=1;i<=n;i++)fact[i]=fact[i-1]*i%mod;
inv[n]=quick_pow(fact[n],mod-2);
for(i=n-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
LL C(int a,int b){//组合数计算
return fact[a]*inv[a-b]%mod*inv[b]%mod;
}
void dfs1(int u,int fa){
int b,v;
sz[u]=1,pre[u]=1;
for(b=head[u];b;b=e[b].next){
v=e[b].to;
if(v==fa)continue;
dfs1(v,u);
sz[u]+=sz[v];
pre[u]=pre[v]*pre[u]%mod*C(sz[u]-1,sz[v])%mod;
}
}
void dfs2(int u,int fa){//换根dp
int b,v;
ans[u]=tp[u]*pre[u]%mod*C(n-1,n-sz[u])%mod;
for(b=head[u];b;b=e[b].next){
v=e[b].to;
if(v==fa)continue;
tp[v]=ans[u]*quick_pow(pre[v]*C(n-1,sz[v])%mod,mod-2)%mod;//v是下一次搜索的根,u是当前的根,tp[v]代表在以v为根时,pre[u]的值。
dfs2(v,u);
}
}
int main(){
init();
dfs1(1,0);
tp[1]=1;
dfs2(1,0);
for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);
return 0;
}