《HDU多校第三场》

Little W and Contest

思路:首先很显然是并查集去维护答案。

一开始,所有点都是独立的。那么设CF1 = 1的总个数。CF2 = 2的总个数

那么一开始ans = C(CF1,1)*C(CF2,2)+C(CF2,3).

那么考虑合并后怎么维护答案。

这里运用了容斥思想。

当我们合并后。我们只需要将之前合法的,现在不合法的答案删去即可。

那么对于不合法的答案:肯定是这两个连通块各选一个,然后和剩下的所有组合。

设合并的两个连通块为x,y。

那么不合法的答案为。

1.C(x2,1)*C(y2,1)*C(除x,y之外的1,1)

2.C(x2,1)*C(y2,1)*C(除x,y之外的2,1)

3.C(x2,1)*C(y1,1)*C(除x,y之外的2,1)

4.C(x1,1)*C(y2,1)*C(除x,y之外的2,1)

删完之后注意合并连通块里的数目

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<int,int> pii;
const int N = 1e5+5;
const int M = 250005;
const LL Mod = 1e9+7;
#define pi acos(-1)
#define INF 1e8
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read()
{
    int x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
LL a[N],x[N],y[N],f[N];//x - 2 ,y - 1.
int fa[N];
void init()
{
    f[0] = 1;for(int i = 1;i < N;++i) f[i] = f[i-1]*i%Mod;
}
int Find(int x)
{
    return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
LL quick_mi(LL a,LL b)
{
    LL re = 1;
    while(b)
    {
        if(b&1) re = (re*a)%Mod;
        a = (a*a)%Mod;
        b >>= 1;
    }
    return re;
}
LL inv(LL n){return quick_mi(n,Mod-2)%Mod;}
LL C(LL n,LL m)
{
    return f[n]*inv(f[n-m])%Mod*inv(f[m])%Mod;
}
int main()
{
    init();
    int ca;ca = read();
    while(ca--)
    {
        int n;n = read();
        memset(x,0,sizeof(x));//2
        memset(y,0,sizeof(y));//1
        int cnt1 = 0,cnt2 = 0;//1,2
        for(int i = 1;i <= n;++i) 
        {
            a[i] = read(),fa[i] = i;
            if(a[i] == 1) y[i]++,cnt1++;
            else x[i]++,cnt2++;
        }
        LL ans = (C(cnt2,2)*C(cnt1,1)%Mod+C(cnt2,3))%Mod;
        printf("%lld\n",ans);
        for(int i = 1;i < n;++i)
        {
            int u,v;u = read(),v = read();
            int xx = Find(u),yy = Find(v);
            int z1 = cnt1-y[xx]-y[yy];
            int z2 = cnt2-x[xx]-x[yy];
            LL ma1,ma2,ma3,ma4;
            if(x[xx] > 0 && x[yy] > 0)//2 2 1
            {
                ma1 = C(x[xx],1)*C(x[yy],1)%Mod*z1%Mod;
                ans = ((ans-ma1)%Mod+Mod)%Mod;
            }
            if(x[xx] > 0 && y[yy] > 0)//2 1 2
            {
                ma2 = C(x[xx],1)*C(y[yy],1)%Mod*z2%Mod;
                ans = ((ans-ma2)%Mod+Mod)%Mod;
            }
            if(x[xx] > 0 && x[yy] > 0)//2 2 2
            {
                ma3 = C(x[xx],1)*C(x[yy],1)%Mod*z2%Mod;
                ans = ((ans-ma3)%Mod+Mod)%Mod;
            }
            if(y[xx] > 0 && x[yy] > 0)///1 2 2
            {
                ma4 = C(y[xx],1)*C(x[yy],1)%Mod*z2%Mod;
                ans = ((ans-ma4)%Mod+Mod)%Mod;
            }
            fa[xx] = yy;//合并
            x[yy] += x[xx];
            y[yy] += y[xx];
            printf("%lld\n",ans);
        }
    }
    system("pause");
    return 0;
}
View Code

Tokitsukaze and Rescue

思路:首先删的边肯定是最短路上的边。

dfs枚举删除最短路上的每条边。

每次删完边后都要跑dij来形成新的最短路。

这里因为每次跑最短路之后pre数组会改变,那么可能影响到上层的pre数组。

所以把pre数组开到dfs局部,这样就互不影响。

因为这里是随机数据,可以猜想形成最短路的边不会特别多,这样可以保证每次枚举删边的边不会很多。

考虑一下平均10条,k最大5,最坏复杂度为5^10左右。

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<int,int> pii;
const int N = 55;
const int M = 250005;
const LL Mod = 1e9+7;
#define pi acos(-1)
#define INF 1e18
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read()
{
    int x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
int n,k;
LL dis[N],road[N][N],ans;
void dij(int *pre)
{
    for(int i = 1;i <= n;++i) dis[i] = INF;
    dis[1] = 0;
    priority_queue<pii,vector<pii>,greater<pii> > Q;
    Q.push(pii{0,1});
    pre[1] = 0;
    while(!Q.empty())
    {
        int u = Q.top().second;
        LL d = Q.top().first;
        Q.pop();
        if(d > dis[u]) continue;
        for(int i = 1;i <= n;++i)
        {
            if(dis[i] > dis[u]+road[u][i])
            {
                pre[i] = u;
                dis[i] = dis[u]+road[u][i];
                Q.push(pii{dis[i],i});
            }
        }
    }
}
void dfs(int num)
{
    int pre[N];
    dij(pre);
    if(num == k+1)
    {
        ans = max(ans,dis[n]);
        return ;
    }
    int now = n;
    while(now != 1)
    {
        LL tmp = road[now][pre[now]];
        road[now][pre[now]] = road[pre[now]][now] = INF;
        dfs(num+1);
        road[now][pre[now]] = road[pre[now]][now] = tmp;
        now = pre[now];
    }
}
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        n = read(),k = read();
        for(int i = 1;i <= n;++i)
            for(int j = 1;j <= n;++j) road[i][j] = INF;
        ans = -1;
        for(int i = 1;i <= n*(n-1)/2;++i)
        {
            int u,v,w;
            u = read(),v = read(),w = read();   
            road[u][v] = road[v][u] = w;
        }
        dfs(1);
        printf("%lld\n",ans);
    }
    system("pause");
    return 0;
}
View Code

 

posted @ 2020-07-29 08:54  levill  阅读(90)  评论(0编辑  收藏  举报