CF283C Coin Troubles

https://www.luogu.com.cn/problem/CF283C

根据限制关系建图转化为一条条链不难想到。

转化后,先按最小情况填满,即叶子为 \(0\),然后增 \(1\) 上去。

考虑让某一个点 \(+1\),那是不是这个点到根的路径上的点都要 \(+1\)

于是对于每个点算出来这个贡献做完全背包即可。

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int mod=(int)(1e9+7),N=305;
vector<int>g[N];
int n,m,t,a[N],num[N],du[N],val[N],id[N];
int f[100005];

bool cmp(const int &x,const int &y) {
	return num[x]<num[y];
}
vector<int>vec[N];
queue<int>q;
signed main() {
	cin.tie(0); ios::sync_with_stdio(false);
	cin>>n>>m>>t;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++) {
		int x,y; cin>>x>>y;
		g[y].pb(x); ++du[x];
	} 
//	int tot=0;
	for(int i=1;i<=n;i++) if(!du[i]) id[i]=i,q.push(i);
	while(!q.empty()) {
		int x=q.front(); q.pop();
		for(int y:g[x]) {
			num[y]=num[x]+1; id[y]=id[x];
			q.push(y);
		}
	}
	for(int i=1;i<=n;i++) {
		if(!id[i]) {
			cout<<"0"; return 0;
		}
	}
	for(int i=1;i<=n;i++) vec[id[i]].pb(i);
	for(int i=1;i<=n;i++) sort(vec[i].begin(),vec[i].end(),cmp);
	for(int i=1;i<=n;i++) {
		int qwq=0;
		for(int j=0;j<vec[i].size();j++) qwq+=j*a[vec[i][j]];
		t-=qwq;
		for(int j=0;j<vec[i].size();j++) {
			qwq=0;
			for(int k=j;k<vec[i].size();k++) qwq+=a[vec[i][k]];
			val[vec[i][j]]=qwq;
		}
	}
	if(t<0) {
		cout<<"0"; return 0;
	}
	f[0]=1;
	for(int i=1;i<=n;i++) {
		for(int j=val[i];j<=t;j++) {
			f[j]=(f[j]+f[j-val[i]])%mod;
		}
	}
	cout<<(f[t]%mod+mod)%mod;
	return 0;
}

// 不妨考虑假如链上一个点增大1,那么显然这个点到根的路径中的每个点+1
// 所以先对于每条链填满根为 sz-1
// 然后计算每个点+1 带来的贡献
// 完全背包即可 
// b>c -> b=c+1,连 (c,b) 入度为0即为0 

posted @ 2022-07-16 18:04  FxorG  阅读(27)  评论(0编辑  收藏  举报