• 那永恒没骗我 离散也没有 这份爱只是活在 另外时空


    那永恒没骗我 离散也没有
    这份爱只是活在 另外时空
    如果 每一声再见 会开启
    一个新的空间
    每做一个梦 是时空 偶尔的重叠
    你好吗 离开的人啊
    请帮我 相爱到剧终
    \(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\) ——周深 《花开忘忧》

    题意

    \(~~~~\) 圆上有 \(2n\) 个点,保证任意选出六个点连边不会交于一点,求有多少连边方案使得连完过后恰有 \(n-1\) 个交点且这些交点形成一棵树.
    \(~~~~\) \(1\leq n\leq 20\).

    题解

    \(~~~~\) 我宣布ubuntu的输入法就算是fcitx也很难用,想办法安个搜狗。

    \(~~~~\) AT 的题不出意外会有一个思路然后这个思路出了意外。

    \(~~~~\) 这题一开始想成共有 \(n\) 个点,自然而然考虑到状压。然后发现可以不关心已经选了的点怎么连的边,因为只要新连边的两个端点跨过了其中一个端点即可。于是有了美好的 \(\mathcal{O(2^n n^3)}\) 的算法,然后发现是 \(2n\) ,然后自闭。

    \(~~~~\) 然后顺着刚刚的思路,我们只需要关心一个区间的端点中间只包含了一个连出去的边,所以我们定义 \(dp[l,r,x]\) 表示 \([l,r]\) 区间内 \(x\) 向区间外连边,其他内部连的方案数。

    \(~~~~\) 然后考虑怎么转移这样一个东西过来,枚举状态 \([l,r,i]\)\(n^3\) ,然后我们枚举两个端点 \(j,k\) 表示这两个端点连边,那么这个端点就会与已经枚举的 \(x\) 有交,这也是唯一的交。然后我们来看更其他的点。可以发现要么这些边的端点在 \(j\) 两侧,要么在 \(i\) 两侧,要么在 \(k\) 两侧。更进一步地,存在两个分割点 \(p,q\) ,使得 \([l,p]\) 内的互相连边,\([p+1,q-1]\) 内的互相连边,\([q,r]\) 内的互相连边,并且甚至我们已经确定了连出去的点,所以我们就得到了三个子问题。

    \(~~~~\) 所以 \(dp_{l,i,r}=dp_{p+1,i,q-1}\times dp_{q,k,r} \times dp_{l,j,p}\times [a_{j,k}=1]\) ,这就有了 \(n^7\) 的转移。

    \(~~~~\) 不过这东西常数挺小然后可以过。

    \(~~~~\)\(g_{l,k,p}=\sum f_{l,j,p}\times [a_{j,k}=1]\) ,这可以在每个状态过后用 \(n^2\) 完成。

    \(~~~~\) 最后只需要每次枚举完状态过后 \(n^2\) 就可以了.

    \(~~~~\) 最后再吐槽一次输入法

    代码

    #include <bits/stdc++.h>
    #define ll long long
    #define PII pair<int,int>
    #define mp(a,b) make_pair(a,b)
    using namespace std;
    template<typename T>void read(T &x)
    {
        T f=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    char Map[45][45];
    ll f[45][45][45],g[45][45][45];
    int main() {
        #ifndef ONLINE_JUDGE
        freopen("input","r",stdin);
        freopen("output","w",stdout);
        #endif
        int n;read(n);n*=2;
        for(int i=1;i<=n;i++) scanf("%s",Map[i]+1);
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) Map[i][j]-='0';
        for(int i=2;i<=n;i++)
        {
            f[i][i][i]=1;
            for(int j=i+1;j<=n;j++) g[i][j][i]=Map[i][j];
        }
        for(int len=3;len<n;len+=2)
        {
            for(int l=2;l+len-1<=n;l++)
            {
                int r=l+len-1;
                for(int p=l;p<=r;p+=2)
                {
                    for(int q=r;q>=l;q-=2)
                    {
                        ll Tmp=0;
                        for(int k=q;k<=r;k++) Tmp+=g[l][k][p]*f[q][k][r];
                        for(int i=p+1;i<q;i++) f[l][i][r]+=f[p+1][i][q-1]*Tmp;
                    }
                }
                for(int i=l;i<=r;i++)
                    for(int j=i+1;j<=n;j++) g[l][j][r]+=Map[i][j]*f[l][i][r];
            }
        }
        ll Ans=0;
        for(int i=2;i<=n;i++) Ans+=Map[1][i]*f[2][i][n];
        printf("%lld",Ans);
        return 0;
    }
    
  • 相关阅读:
    洛谷 P2766 最长不下降子序列问【dp+最大流】
    洛谷 P3254 圆桌问题【最大流】
    洛谷 P2764 最小路径覆盖问题【匈牙利算法】
    洛谷 P2763 试题库问题【最大流】
    洛谷 P2762 太空飞行计划问题 【最大权闭合子图+最小割】
    洛谷 P2761 软件补丁问题 【spfa】
    洛谷 P2754 星际转移问题【最大流】
    洛谷 P1251 餐巾计划问题【最小费用最大流】
    spoj 371 Boxes【最小费用最大流】
    poj 3680 Intervals【最小费用最大流】
  • 原文地址:https://www.cnblogs.com/Azazel/p/16724588.html
Copyright © 2020-2023  润新知