• 7.12 NOI模拟赛 生成树 装压dp vector装压


    LINK:生成树

    avatar
    avatar

    这场比赛我打的真失败 T3是比较容易的 却一直刚 那道"数论"

    10分其实搜一下全排列。

    30分容易想到对边进行装压dp。

    不过存在一些细节 可以对于一个连通块的壮大进行装压 也就是每次需要联通两个块的时候使用关键边 然后再这两个块之间加边知道加满需要其他边。

    复杂度 (2^{21}cdot 21cdot 6) 可能能过或许是我的做法不太行?

    值得一提的是这样是无标号的需要最后乘以一个阶乘.

    可以发现之所以装压边是为了防止 一些边的添加使得最小生成树变化。

    可以考虑从小到大加边 是关键边就连接两个连通块 不是的话就添加到联通块的内部。

    可以考虑对连通块进行装压 可以发现所以可能的情况只有3e5左右种.

    那么就有(f_{i,j})表示加到i条边连通块的情况为j的方案数.

    将边从小到大排序就不需要考虑 且按照上述策略就一定不会改变最小生成树的形态.

    当第i条边需要连接联通块的时候 可以在 状态中的两个联通块中选出两个连边就行辣 这部分复杂度 (n^3)不过很大程度上是跑不满的。

    当需要连到联通块的内部的时候 那就预处理一下当前状态 能在连通块中加多少条边即可。转移的复杂度为O(1).

    因为每个状态最多连边一次 所以

    总复杂度(ncdot S+Scdot n^3)不过是跑不满的 n^3.

    可以通过!

    code
    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 10000000000000000ll
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-4
    #define sq sqrt
    #define S second
    #define F first
    #define mod 1000000007
    #define V vector<int>
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=40010,maxn=40*40/2;
    int f[maxn][MAXN];
    V g[MAXN],now;
    map<V,int>H;
    int vis[maxn],w[MAXN];
    int n,m,id;
    inline void add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
    inline int mul(int x,int y){return (ll)x*y%mod;}
    inline void dfs(int x,int res)
    {
    	if(!res)
    	{
    		H[now]=++id;g[id]=now;
    		vep(0,now.size(),j)w[id]+=(now[j]*(now[j]-1))/2;
    		return;
    	}
    	if(x>res)return;
    	now.pb(x);
    	dfs(x,res-x);
    	now.pop_back();
    	dfs(x+1,res);
    }
    int main()
    {
    	freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
    	get(n);m=n*(n-1)/2;
    	rep(1,n-1,i)vis[read()]=1;
    	dfs(1,n);
    	f[0][1]=1;
    	rep(1,m,i)
    	{
    		rep(1,id,j)if(f[i-1][j])
    		{	
    			if(vis[i])
    			{
    				vep(0,g[j].size(),l)
    				vep(l+1,g[j].size(),r)
    				{
    					now.clear();
    					vep(0,g[j].size(),k)if(k!=l&&k!=r)now.pb(g[j][k]);
    					now.pb(g[j][l]+g[j][r]);
    					sort(now.begin(),now.end());
    					int ww=H[now],cc=mul(g[j][l],g[j][r]);
    					add(f[i][ww],mul(cc,f[i-1][j]));
    				}
    			}
    			else add(f[i][j],mul(f[i-1][j],w[j]-i+1));
    		}
    	}
    	put(f[m][id]);return 0;
    }
    
  • 相关阅读:
    基于傅里叶变换的音频重采样算法 (附完整c代码)
    自动曝光修复算法 附完整C代码
    3D Lut 电影级调色算法 附完整C代码
    之于图片主色调提取算法
    并发中的各种锁
    算法---BitMap
    高级数据结构---堆树和堆排序
    高级数据结构---赫(哈)夫曼树及java代码实现
    域名和服务器绑定及https协议更换
    高级数据结构---B树和B+树及mysql索引分析
  • 原文地址:https://www.cnblogs.com/chdy/p/13308872.html
Copyright © 2020-2023  润新知