2020暑假杭电 第三场 1005+1009 并查集+数学

1005 Little W and Contest

题目

http://acm.hdu.edu.cn/showproblem.php?pid=6795

题意

给定n个点,有两种点,权值分别为1和2,

初始时,n个点互不相连。初始时,n个点互不相连。初始时,n个点互不相连。

接着会加入n−1条边,保证每次加入的边的两个端点事先是不相连通的。

要从中选择3个点,满足3个点的权值之和不少于5,且3个点之间互不相连,计算出不同的选择方案的数量。

每加入一条边,都要输出当前连通状态下,不同的选择方案的数量。

题解

初始状态的计算:假设权值为1的点的数量为cnt1​,权值为2的点的数量为cnt2​,

此时的不同方案的总数:
ans = C2cnt2 x C1cnt1 + C3cnt2

我们考虑每次添加一条边后,会有哪一部分的方案会变成不合法的方案

由于每次加边合并都是对两个连通块进行操作,假设现在u和v之间添加一条边

因此,我们将n个点分为3个部分:u所在连通块Gu、v所在的连通块Gv、其他剩余点Gr

不合法的方案有以下四种:

(1)Gu选择一个权值为1的点,Gv选择一个权值为2的点,Gr选择一个权值为2的点。

(2)Gu选择一个权值为2的点,Gv选择一个权值为1的点,Gr选择一个权值为2的点。

(3)Gu选择一个权值为2的点,Gv选择一个权值为2的点,Gr选择一个权值为2的点。

(4)Gu选择一个权值为2的点,Gv选择一个权值为2的点,Gr选择一个权值为1的点。

参考博客:https://blog.csdn.net/njuptACMcxk/article/details/107641773

AC代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int mod = 1e9+7;
int pre[maxn],a[maxn],p1[maxn],p2[maxn];
ll g1[maxn],g2[maxn];
int find(int x)//找到根节点
{
    return pre[x] == x ? x : find(pre[x]);
//    return pre[x] < 0 ? x : find(pre[x]);
}
void merge(int x, int y)//x和y做朋友
{
    int fx = find(x), fy = find(y);//找到x和y的根节点
    if (fx != fy)//x,y不是同一个人
    {
//        pre[fy] += pre[fx];//人数是两个之和
        pre[fx] = fy;//合并
    }
}
ll C2(int n)
{
    if(n<2) return 0;
    return (ll)(n-1)*n/2%mod;
}

ll C3(int n)
{
    if(n<3) return 0;
    return (ll)(n)*(n-1)*(n-2)/6%mod;
}
int main()
{
//    freopen("1009.txt", "r", stdin);   // 读入刚写的文件
//    freopen("1009zhz.out", "w", stdout);  // 输出将要输出的数据
    int T;
    int cnt=1;
    scanf("%d",&T);
    while(T--)
    {
        int n,cnt1=0,cnt2=0;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            pre[i]=i;
            scanf("%d",&a[i]);
            if(a[i]==1) 
            {
                cnt1++;
                p1[i]=1;
                p2[i]=0;    
            }
            else
            {
                cnt2++;
                p1[i]=0;
                p2[i]=1;        
            }
        }
        ll ans = (C2(cnt2)*cnt1%mod+C3(cnt2))%mod;
        printf("%lld\n",ans);
        for(int i=0; i<n-1; i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            int fu=find(u),fv=find(v);
            int k = 0;
            k=(k+(ll)p1[fu]*p2[fv]*(cnt2-p2[fu]-p2[fv]))%mod;
    
            k=(k+(ll)p2[fu]*p1[fv]*(cnt2-p2[fu]-p2[fv]))%mod;
            
            k=(k+(ll)p2[fu]*p2[fv]*(cnt2-p2[fu]-p2[fv]))%mod;
            
            k=(k+(ll)p2[fu]*p2[fv]*(cnt1-p1[fu]-p1[fv]))%mod;
            ans = (ans-k+mod)%mod;
            printf("%lld\n",ans);
            merge(u,v);
            p1[fv]+=p1[fu], p2[fv]+=p2[fu];
            p1[fu]=0, p2[fu]=0;
        }
    }
    return 0;
}
/*
1
5
2 2 2 1 1
4 5
1 4
2 1
3 2

*/

1009 Parentheses Matching

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=6799

题意

给字符串s,s含有:( ) * 三种字符。你可以将 * 转化成左右括号,或者不转换。s求符合括号匹配的情况下,最小的字典序并输出。没有答案输出"No solution!"

题解

优先从左边把星星改为左括号,完成右括号的匹配。
在把从右边把星星改为右括号,完成左括号的匹配。
这样字典序就保证最小了。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
using namespace std;
typedef long long ll;
const int maxn = 100005;
char s[maxn];
int l[maxn],r[maxn],local[maxn];
int main()
{
//    freopen("1009.txt", "r", stdin);   // &#182;áè&#235;&#184;&#213;D′μ&#196;&#206;&#196;&#188;t
//    freopen("1009zhz.out", "w", stdout);  // ê&#228;3&#246;&#189;&#171;òaê&#228;3&#246;μ&#196;êy&#190;Y
    int T;
    int cnt=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",s);
        int len = strlen(s);
//        if(cnt==8708)
//            puts(s);
        int lena=0,lenb=0,star=0;
        for(int i=0; i<len; i++)
        {
            if(s[i]=='(')
                l[lena++]=i+1;
            else if(s[i]==')')
                r[lenb++]=i+1;
            else
                local[star++]=i+1;
        }
        l[lena]=0;
        r[lenb]=0;
        local[star]=0;
        bool falg = true;
        int beg=0;
        bool next = true;
        for(int i=0,j=0; i<lenb; i++)
        {
            if(l[j]<r[i]&&l[j]!=0)
                j++;
            else
            {
                if(star==beg)
                    falg = false;
                for(int z=beg; z<star; z++)
                {
                    if(local[z]<r[i])
                    {
                        s[local[z]-1] = '(';
                        beg++;
                        break;
                    }
                    else if(z+1==star)
                        falg = false;
                }
            }
            if(j+1>lena)
            {
                next = false;
            }

        }
        if(next)
            for(int i=lena-1,j=lenb-1; i>=0; i--)
            {
                if(l[i]<r[j])
                    j--;
                else
                {
                    if(star==beg)
                        falg = false;
                    for(int z=star-1; z>=beg; z--)
                    {
                        if(local[z]>l[i])
                        {
                            s[local[z]-1] = ')';
                            star--;
                            break;
                        }
                        else if(z==beg)
                            falg = false;
                    }
                }
            }
        if(falg)
        {
            for(int i=0; i<len; i++)
            {
                if(s[i]!='*')
                    printf("%c",s[i]);
            }
            puts("");
        }
        else
        {
            puts("No solution!");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43911945/article/details/107670331