题解:AT_codefestival_2016_final_f Road of the King
_zuoqingyuan · · 题解
啊呀。
我们考虑一下对这个东西计数,要维护是什么抽象的东西。
先假设当前走了
红点就是
注意到我们实际走到哪个节点时无意义的,所以不需要记录这个东西。考虑接下来第
- 首先可能走到一个新的点,得到一个新的 scc。
这个黄点可以选择的方案数是
- 其次可能走到一个之前走过的点,先考虑特殊的,我们走到了
1 所在的 scc 内的一个点,此时我们走到的所有点都会缩成一个 scc。
这一步可以走的方案数是
- 最后,是走到一个没走到的点的其他情况,我们把一些蓝色点缩成了一个 scc。
这一步以走的方案数是蓝色点 scc 内的点数之和,不难发现我们并不关注每个蓝色 scc 点内的具体点数,只关心和。
整合思路,设
第一种转移,其实是新增加了一个蓝点:
第二种转移,实际上是将一堆蓝色点变成一个蓝色点,蓝色点的总点数是不变的:
第三种转移,将所有的蓝色点变成一个红色点了,转移即可:
不难发现确定状态后,状态的转移是
#include <iostream>
#include <cstdio>
using namespace std;
const int N=305;
const int mod=1e9+7;
typedef long long ll;
int n,m;
ll f[N][N][N];
int main(){
cin>>n>>m;
f[0][0][1]=1;
for(int i=0;i<m;i++){
for(int j=0;j<=n;j++){
for(int k=0;k<=n-j;k++){
if(!f[i][j][k])continue;
f[i+1][j+1][k]+=f[i][j][k]*(n-j-k)%mod;
f[i+1][j+1][k]%=mod;
f[i+1][j][k]+=f[i][j][k]*j%mod;
f[i+1][j][k]%=mod;
f[i+1][0][j+k]+=f[i][j][k]*k%mod;
f[i+1][0][j+k]%=mod;
}
}
}
cout<<f[m][0][n]<<endl;
return 0;
}
如有错误,请指出。