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