【题解】【CF283C Coin Troubles】

好坑的一道题。。。

Solution

首先很容易联想到完全背包计算方案数,考虑如何维护严格大于的限制。
把限制看作一条有向边,题目保证每个点入度,出度均不超过1,则最终的图一定是若干个链或环。若存在环一定无解。
那么对于每条链分别考虑,每条链中最小的点最少选0个,第二小的最少选1个,···第i小的最少选i-1个,先把这些必选的选完,直接在t里面扣即可。
然后对于任意一个点,若选一次这个点,必须把所有大于它的都选一次,因此,可以将必选同时选的物品打包,价值是一个后缀和,然后做完全背包即可。
但是一开始每想到环的情况。。。

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
	int x=0,w=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
inline void write(int x)
{
	if(x<0) putchar('-'),x=~(x-1);
	if(x>9) write(x/10);
	putchar('0'+x%10);
}
const int N=1e5+100,mod=1e9+7;
int a[305],t,w[305],f[N],cnt,sum,n,q,vis[305];
vector<int>v[305];
int ind[305];
void dfs(int x,int tot)
{
	t-=tot*a[x];vis[x]=1;
	if(v[x].size()==0){
		sum+=a[x];w[++cnt]=sum;return;
	}
	dfs(v[x][0],tot+1);sum+=a[x];w[++cnt]=sum;
}
signed main()
{
    n=read();q=read();t=read();
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=q;++i)
    {
    	int x=read(),y=read();
    	v[y].push_back(x);ind[x]++;
	}
	for(int i=1;i<=n;++i){
		if(ind[i]==0){
			sum=0;
			dfs(i,0);
		}
	}
	for(int i=1;i<=n;++i){
		if(vis[i]==0){
			puts("0");return 0;
		}
	}
	if(t<0){
		puts("0");return 0;
	}
	f[0]=1;
	for(int i=1;i<=cnt;++i){
		for(int j=w[i];j<=t;++j)
		{
			f[j]+=f[j-w[i]];f[j]%=mod;
		}
	}
	write(f[t]);
	return 0;
}
posted @ 2022-05-05 08:25  glq_C  阅读(38)  评论(0)    收藏  举报