【题解】洛谷 P6651 「SWTR-05」Chain | 20211011 模拟赛 食物链(foodchain)【拓扑排序 容斥】

题目链接

题目链接

题意

对于 DAG,定义一条食物链为其极长路径。多次询问,删除 (k) 个点,剩余多少原有的食物链。(nleq 2 imes 10^3,sum kleq 2 imes 10^6)

题解

添加超级源汇点以方便处理。预处理 (i)(j) 的路径数,(2^k) 容斥显然,按照拓扑序排序后 DP 则 (O(k))

#include<bits/stdc++.h>
using namespace std;
const int BUF_SIZ=20*1024*1024;
char buf[BUF_SIZ],*cur=buf;
int getint(){
	int ans=0;
	char c=*cur++;
	while(c<'0'||c>'9')c=*cur++;
	while(c>='0'&&c<='9'){
		ans=ans*10+c-'0';
		c=*cur++;
	}
	return ans;
}
void putint(int x){
	if(x==0){
		putchar('0');
		return;
	}
	if(x/10)putint(x/10);
	putchar(x%10+'0');
}
const int N=2e3+10,mod=1e9+7;
int _(int x){ return x>=mod?x-mod:x; }
vector<int>to[N];
int deg[N],ged[N];
int p[N],rk[N];
int f[N][N];
int g[20];

int main(){
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	freopen("foodchain.in","r",stdin);
	freopen("foodchain.out","w",stdout);
	fread(buf,BUF_SIZ,1,stdin);
	int n=getint(),m=getint();
	for(int i=0;i<m;i++){
		int x=getint(),y=getint();
		to[x].push_back(y);
		++deg[y];
		++ged[x];
	}
	for(int i=1;i<=n;i++){
		if(deg[i]==0){
			to[0].push_back(i);
			++deg[i];
			++ged[0];
		}
		if(ged[i]==0){
			to[i].push_back(n+1);
			++deg[n+1];
			++ged[i];
		}
	}
	queue<int>q;
	q.push(0);
	int tmp=0;
	while(q.size()){
		int t=q.front();q.pop();
		rk[t]=tmp;
		p[tmp++]=t;
		for(int i:to[t]){
			--deg[i];
			if(!deg[i])q.push(i);
		}
	}
	for(int i=0;i<=n+1;i++){
		int *g=f[i];
		g[i]=1;
		for(int j=0;j<=n+1;j++){
			for(int k:to[p[j]])
				g[k]=_(g[k]+g[p[j]]);
		}
	}
	
	int Q=getint();
	while(Q--){
		int k=getint();
		vector<int>v;
		v.push_back(0);
		for(int i=0;i<k;i++)v.push_back(getint());
		v.push_back(n+1);
		sort(v.begin(),v.end(),[&](int x,int y){ return rk[x]<rk[y]; });
		g[0]=mod-1;
		for(int i=1;i<=k+1;i++){
			g[i]=0;
			for(int j=0;j<i;j++)
				g[i]=(g[i]+g[j]*1ll*(mod-f[v[j]][v[i]]))%mod;
		}
		putint(g[k+1]);
		putchar('
');
	}
	return 0;
}


知识共享许可协议
若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
原文地址:https://www.cnblogs.com/wallbreaker5th/p/15394640.html