zoukankan      html  css  js  c++  java
  • 「SWTR-05」Chain

    Description

    给定一个 DAG,每次询问如果删除 (kleq 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
    ",ans);
        }
    }
    
  • 相关阅读:
    ajax原理及封装
    javascript 递归调用
    CSS的五种定位方式
    vue中iframe结合window.postMessage实现父子页面间的通信
    vue将文件流的形式的图形验证码转换成图片
    路由跳转打开新窗口,传递的参数不显示在地址栏
    js判断是否是ie浏览器、360浏览器兼容模式、QQ浏览器兼容模式、搜狗浏览器兼容模式,弹出提示使用别的浏览器打开
    vue项目中使用iframe嵌入静态页面,动态获取静态页面的高度赋值给iframe的高度
    vue项目中使用iview组件中的table插件实现表头文字居中,内容文字居左
    vue前端开发实现微信支付和支付宝支付
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15394254.html
Copyright © 2011-2022 走看看