1 条题解

  • 0
    @ 2025-8-24 22:08:36

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Great_Influence
    **

    搬运于2025-08-24 22:08:36,当前版本为作者最后更新于2019-03-05 15:11:45,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    暴力能 A 的迷之题目。

    题意可以理解为给你几棵小树,然后将这几颗小树连成一个环,使得环长 Y\ge Y ,求满足要求的树个数。

    因为数据范围很小,考虑直接用 dfsdfs 将每棵小树内的所有路径都统计出来。然后就变成了问给你几个集合,从这些集合中每个集合选择一个数,问和 Y\ge Y 的方案和。这是一个简单背包问题。求方案和可以顺便求出。

    具体来说,设 dp[i][0/1]dp[i][0/1] 表示 和为 ii 的方案数/方案和, g[i][0/1]g[i][0/1] 表示当前小树内长度为 ii 的路径数/长度和,则存在转移:

    dp[i+j][0]dp[i][0]g[j][0]dp[i+j][0]\leftarrow dp[i][0]*g[j][0] $$dp[i+j][1]\leftarrow dp[i][0]*g[j][1] + dp[i][1]*g[j][0] $$

    直接转移即可。

    注意我们并不关注这个长度具体是多少,只关注它是否比 YY 大。并且长度大于等于 YY 的方案之后再怎么变都是满足要求的。因此可以将长度 Y\ge Y 的部分记在一起。还有个优化是可以直接从 XkX*k 开始转移。还有就是只转移 ggdpdp 有值的位置。

    时间复杂度为 O(ni2+min{Y,ni2}(YXK))=O(NYY)O(\sum n_i^2+\min\{Y,n_i^2\}(Y-XK))=O(NY\sqrt{Y})nin_i 为第 ii 棵小树的点数。复杂度证明为考虑子树贡献,当 i,Y=ni2\forall i,Y=n_i^2时复杂度取得最大值。

    代码:

    #include<bits/stdc++.h>
    #define Rep(i,a,b) for(register int i=(a);i<=(b);++i)
    #define Repe(i,a,b) for(register int i=(a);i>=(b);--i)
    #define rep(i,a,b) for(register int i=(a);i<(b);++i)
    #define pb push_back
    #define mx(a,b) (a>b?a:b)
    #define mn(a,b) (a<b?a:b)
    typedef unsigned long long uint64;
    typedef unsigned int uint32;
    typedef long long ll;
    using namespace std;
    
    namespace IO
    {
    	const uint32 Buffsize=1<<15,Output=1<<24;
    	static char Ch[Buffsize],*S=Ch,*T=Ch;
    	inline char getc()
    	{
    		return((S==T)&&(T=(S=Ch)+fread(Ch,1,Buffsize,stdin),S==T)?0:*S++);
    	}
    	static char Out[Output],*nowps=Out;
    	
    	inline void flush(){fwrite(Out,1,nowps-Out,stdout);nowps=Out;}
    
    	template<typename T>inline void read(T&x)
    	{
    		x=0;static char ch;T f=1;
    		for(ch=getc();!isdigit(ch);ch=getc())if(ch=='-')f=-1;
    		for(;isdigit(ch);ch=getc())x=x*10+(ch^48);
    		x*=f;
    	}
    
    	template<typename T>inline void write(T x,char ch='\n')
    	{
    		if(!x)*nowps++='0';
    		if(x<0)*nowps++='-',x=-x;
    		static uint32 sta[111],tp;
    		for(tp=0;x;x/=10)sta[++tp]=x%10;
    		for(;tp;*nowps++=sta[tp--]^48);
    		*nowps++=ch;
    	}
    }
    using namespace IO;
    
    void file(void)
    {
    	FILE*DSD=freopen("water.in","r",stdin);
    	FILE*CSC=freopen("water.out","w",stdout);
    }
    
    const int MAXN=1500+7,MAXY=2500+7,mod=1e9+7;
    
    static int n,m;
    
    static struct edge
    {
    	int v,w,nxt;
    }p[MAXN<<1];
    
    static int head[MAXN],e;
    
    inline void add(int u,int v,int w)
    {p[++e]=(edge){v,w,head[u]},head[u]=e;}
    
    namespace DSU
    {
    	static int fa[MAXN];
    
    	inline void clear(){Rep(i,1,n)fa[i]=i;}
    
    	inline int Find(int u){return u==fa[u]?u:fa[u]=Find(fa[u]);}
    }
    
    static int X,Y;
    
    inline void init()
    {
    	read(n),read(m),read(X),read(Y);
    	DSU::clear();
    	static int u,v,w;
    	Rep(i,1,m)read(u),read(v),read(w)
    		,add(u,v,w),add(v,u,w),DSU::fa[DSU::Find(u)]=DSU::Find(v);
    }
    
    static int cn;
    
    static int bel[MAXN],dst[MAXN][MAXY],sig[MAXN][MAXY];
    
    void dftag(int u,int fr,int dir)
    {
    	bel[u]=dir;
    	for(register int i=head[u];i;i=p[i].nxt)
    	{
    		int v=p[i].v;
    		if(v^fr)dftag(v,u,dir);
    	}
    }
    
    void dffix(int u,int fr,int len)
    {
    	if(fr)(sig[bel[u]][min(Y,len)]+=len)%=mod,++dst[bel[u]][min(Y,len)];
    	for(register int i=head[u];i;i=p[i].nxt)
    	{
    		int v=p[i].v;
    		if(v^fr)dffix(v,u,len+p[i].w);
    	}
    }
    
    static int dp[MAXY][2],las[MAXY][2];
    
    inline int fac(int u)
    {
    	register int sm=1;
    	Rep(i,2,u)sm=(ll)sm*i%mod;
    	return sm;
    }
    
    inline void solve()
    {
    	Rep(i,1,n)if(DSU::Find(i)==i)++cn,dftag(i,0,cn);
    	Rep(i,1,n)dffix(i,0,0);
    	static int st=min(Y,X*cn);
    	dp[st][0]=1,dp[st][1]=X*cn;
    	Rep(i,1,cn)
    	{
    		Rep(j,st,Y)las[j][0]=dp[j][0]
    			,las[j][1]=dp[j][1],dp[j][0]=dp[j][1]=0;
    		Rep(j,0,Y)if(dst[i][j])Rep(k,st,Y)if(las[k][0])
    		{
    			dp[min(j+k,Y)][0]=(dp[min(j+k,Y)][0]+
    				(ll)las[k][0]*dst[i][j])%mod;
    
    			dp[min(j+k,Y)][1]=(dp[min(j+k,Y)][1]+
    				(ll)las[k][0]*sig[i][j]+(ll)las[k][1]*dst[i][j])%mod;
    		}
    	}
    	cout<<(ll)dp[Y][1]*fac(cn-1)%mod*((mod+1)/2)%mod<<endl;
    }
    
    int main()
    {
    	file();
    	init();
    	solve();
    	return 0;
    }
    
    • 1

    信息

    ID
    4219
    时间
    3000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者