• 【CSP-S 2019模拟】T2—仙人球(仙人掌+背包)


    传送门


    感觉主要还是因为没做过仙人掌的题吧

    还是很简单的一个背包
    把每个环提出来,定一个根
    拆环为链

    计算不经过根的

    否则就肯定是根开始左右分别一段
    记录前后缀拼起来
    强制一边必须选到某个位置,另一边就是一个前缀和

    复杂度O(nk2)O(nk^2)

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    inline char gc(){
        static char ibuf[RLEN],*ib,*ob;
        (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ob==ib)?EOF:*ib++;
    }
    inline int read(){
        char ch=gc();
        int res=0,f=1;
        while(!isdigit(ch))f^=ch=='-',ch=gc();
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
        return f?res:-res;
    }
    #define ll long long
    #define re register
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    #define cs const
    #define bg begin
    #define poly vector<int>
    cs int mod=1e9+7;
    inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
    inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
    inline int mul(int a,int b){return 1ll*a*b%mod;}
    inline void Add(int &a,int b){(a+=b)>=mod?a-=mod:0;}
    inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
    inline void Mul(int &a,int b){a=1ll*a*b%mod;}
    inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
    inline int Inv(int x){return ksm(x,mod-2);}
    inline void chemx(int &a,int b){a<b?a=b:0;}
    inline void chemn(int &a,int b){a>b?a=b:0;}
    cs int N=5005,C=105;
    vector<int> e[N];
    int f[N][C],pre[N][C],suf[N][C];
    int dfn[N],tim,bel[N],cnt,isrt[N];
    int n,m,k,vis[N],fa[N],from[N],ans;
    vector<int> pt[N];
    void tarjan(int u,int fa){
    	dfn[u]=++tim;
    	for(int &v:e[u]){
    		if(v==fa)continue;
    		if(!dfn[v])from[v]=u,tarjan(v,u);
    		else if(dfn[v]<dfn[u]){
    			cnt++,isrt[v]=1,bel[v]=cnt;
    			for(int x=u;x!=v;x=from[x])bel[x]=cnt,pt[cnt].pb(x);
    		}
    	}
    }
    int tmp[C],tmp2[C];
    inline void dp(int *A,int *B,int *C){
    	for(int x=k;x;x--)
    	for(int y=1;y<x;y++)Add(A[x],mul(B[y],C[x-y]));
    }
    inline void calc(int u){
    	poly now=pt[bel[u]];
    	int n=now.size()-1;
    	memcpy(tmp,f[now[0]],sizeof(tmp));
    	for(int i=1;i<=n;i++)memset(pre[i],0,sizeof(suf[i]));
    	for(int i=0;i<n;i++)memset(suf[i],0,sizeof(suf[i]));
    	for(int i=1;i<=n;i++){
    		memset(tmp2,0,sizeof(tmp2));
    		dp(tmp2,tmp,f[now[i]]);
    		memcpy(tmp,tmp2,sizeof(tmp));
    		for(int x=2;x<=k;x++)Add(ans,tmp[x]);
    		for(int x=1;x<=k;x++)Add(tmp[x],f[now[i]][x]);
    	}
    	memcpy(pre[0],f[now[0]],sizeof(f[now[0]]));
    	for(int i=1;i<=n;i++)
    		dp(pre[i],pre[i-1],f[now[i]]);
    	memcpy(suf[n],f[now[n]],sizeof(f[now[n]]));
    	for(int i=n-1;~i;i--)
    		dp(suf[i],suf[i+1],f[now[i]]);
    	memset(tmp,0,sizeof(int)*(k+1));
    	for(int i=0;i<=n;i++)
    	for(int j=1;j<=k;j++)
    		Add(tmp[j],pre[i][j]);
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=k;j++)
    		Add(tmp[j],suf[i][j]);
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=k;j++)
    		Add(pre[i][j],pre[i-1][j]);
    	for(int i=0;i<=n-2;i++)
    		dp(tmp,pre[i],suf[i+2]);
    	dp(f[u],f[u],tmp);
    }
    inline void getans(int u){
    	for(int i=1;i<=k;i++)Add(ans,f[u][i]);
    }
    void dfs(int u){
    	vis[u]=1,f[u][1]=1;
    	for(int &v:e[u]){
    		if(vis[v])continue;
    		dfs(v);
    		if(!bel[u]||bel[u]!=bel[v])
    		dp(f[u],f[u],f[v]);
    	}
    	if(isrt[u])calc(u);
    	getans(u);
    }
    int main(){
    	n=read(),m=read(),k=read();
    	for(int i=1;i<=m;i++){
    		int u=read(),v=read();
    		e[u].pb(v),e[v].pb(u);
    	}
    	tarjan(1,0);
    	dfs(1);
    	cout<<ans<<'
    ';
    } 
    
  • 相关阅读:
    linux基础——文件的压缩解压缩以及vim编辑
    linux基础——关于chmod用户权限和文件的相关操作
    linux基础的基础命令操作
    操作系统和网络基础之网络协议
    计算机基础
    【python小记】访问mysql数据库
    Qt去掉treeview项的焦点虚线
    嵌入式qt显示中文和隐藏鼠标
    【vim小记】自动保存配置
    重回ubutntu12.04小记(装完ubuntu做的几件事)
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328527.html
Copyright © 2020-2023  润新知