【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<<'\n';
} 
posted @ 2019-09-11 21:41  Stargazer_cykoi  阅读(119)  评论(0编辑  收藏  举报