ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「SWTR-05」Chain

2021-10-11 17:31:16  阅读:199  来源: 互联网

标签:个点 Chain 05 int 容斥 拓扑 SWTR include dp


Description

给定一个 DAG,每次询问如果删除 \(k\leq 15\) 个点,还剩下多少条入度为零的点到出度为零的点的路径。新增的路径不参与统计。

Solution

唯一可做题,其他的都没什么思路/kel。

\(k\) 很小,容易想到一个枚举子集的做法,那么只需要预处理出每两个点之间的距离。可以按拓扑序删点,然后再一遍拓扑求出所有点到当前点的距离。配合容斥可以过前 75%,复杂度 \(O(nm+q2^k)\)。

发现只需要知道最后一个点是哪个点,把这 \(k\) 个点按拓扑序排序,然后考虑 dp。\(dp_{i,j}\) 表示选了 \(j\) 个点,最后一个点是第 \(i\) 个的从入度为零的点到 \(i\) 的路径条数。那么统计答案就只需要乘上 \((-1)^j\) 的容斥系数,再乘上点到终点的方案数。这样单次询问就是 \(O(k^3)\)。

再次观察,发现并不需要知道选了多少个,只需要在转移的时候容斥,那么就可以删掉一维。单次 \(O(k^2)\)。

#include<stdio.h>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

const int N=2e3+7;
const int Mod=1e9+7;

queue<int> Q;
vector<int> G[N];
int dfn[N],in[N],dis[N][N],In[N],a[N],dp[16];

inline bool Cmp(int x,int y){return dfn[x]<dfn[y];}

int main(){
    freopen("foodchain.in","r",stdin);
    freopen("foodchain.out","w",stdout);
    int n=read(),m=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        G[u].push_back(v),In[v]++;
    }
    for(int u=1;u<=n;u++){
        if(!G[u].size()) G[u].push_back(n+1),In[n+1]++;
        if(!In[u]) G[0].push_back(u),In[u]++;
        in[u]=In[u];
    }
    Q.push(0); int timer=0;
    while(!Q.empty()){
        int u=Q.front(); Q.pop(); dfn[u]=++timer;
        for(int v:G[u]) if(!(--in[v])) Q.push(v);
    }
    for(int i=0;i<=n+1;i++) a[i]=i;
    sort(a,a+1+n+1,Cmp);
    for(int i=0;i<=n+1;i++){
        const int U=a[i];
        for(int v=0;v<=n+1;v++) in[v]=In[v];
        dis[U][U]=1;
        for(int j=i;j<=n+1;j++)
            if(!in[a[j]]) Q.push(a[j]);
        while(!Q.empty()){
            int u=Q.front(); Q.pop();
            for(int v:G[u]){
                dis[U][v]=(dis[U][v]+dis[U][u])%Mod;
                if(!(--in[v])) Q.push(v);
            }
        }
        for(int v:G[U]) --In[v];
    }
    int q=read();
    while(q--){
        int k=read();
        for(int i=1;i<=k;i++) a[i]=read();
        sort(a+1,a+1+k,Cmp);
        for(int i=1;i<=k;i++)
            dp[i]=Mod-dis[0][a[i]]; 
        for(int i=1;i<=k;i++)
        for(int j=1;j<i;j++)
            dp[i]=(dp[i]-1ll*dp[j]*dis[a[j]][a[i]]%Mod+Mod)%Mod;
        int ans=dis[0][n+1];
        for(int i=1;i<=k;i++)
            ans=(ans+1ll*dp[i]*dis[a[i]][n+1]%Mod)%Mod;
        printf("%d\n",ans);
    }
}

标签:个点,Chain,05,int,容斥,拓扑,SWTR,include,dp
来源: https://www.cnblogs.com/wwlwQWQ/p/15394254.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有