标记的连接图 - dp

题目大意:对所有n个点的无向连通图求1到2的最短路并求和, n ≤ 400 n\le400 n400
题解:首先转化为1到所有点都距离和,最后除以n-1。
然后一个直接dp是直接分层,这样是四次的。
一个做法是你倒着去分层,这样每次往前新增一层,后面所有点的距离+1。
另一个做发是假定当前没加进去的距离都是当前层数+1,然后每次添加一些点,没有被添加的点距离+1。还有一个做法是直接维护……

#include
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<
#define sp <<" "
#define ln <
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=410;int C[N][N],mi[N*N],qwq[N][N],f[N][N],g[N][N],mod;
inline void updl(int &x,lint y) { x=(x+y)%mod; }
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int prelude(int n)
{
    rep(i,0,n) rep(j,C[i][0]=1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    rep(i,mi[0]=1,n*n) mi[i]=mi[i-1]*2%mod;
    rep(i,1,n) rep(j,1,n-i) qwq[i][j]=fast_pow(mi[i]-1,j);
    return 0;
}
int main()
{
    int n=inn(),ans=0;mod=inn(),prelude(n);
    rep(i,1,n-1) g[i][i]=(lint)C[n-1][i]*mi[C[i][2]]%mod;
    rep(i,1,n-1) rep(j,1,i) if(f[i][j]||g[i][j]) rep(k,1,n-1-i)
    {
        int t=(lint)C[n-1-i][k]*qwq[k][j]%mod*mi[C[k][2]]%mod;
        updl(f[i+k][k],((lint)g[i][j]*i%mod+f[i][j])*t),
        updl(g[i+k][k],(lint)g[i][j]*t);
    }
    rep(i,1,n-1) updl(ans,(n-1ll)*g[n-1][i]+f[n-1][i]);
    ans=(lint)ans*fast_pow(n-1,mod-2)%mod;return !printf("%d\n",ans);
}

你可能感兴趣的:(DP动态规划)