题意
对于 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;
}