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
#include
#include
#include
#include

#define ll long long

using namespace std;

const int N=1e5+10, mod=1e9+7;

int T,n;
int w[N];
int cnt[3];
int p[N];
int p1[N],p2[N];

int Find(int x)
{
    if(p[x]!=x) p[x]=Find(p[x]);
    return p[x];
}

int C_2(int n)
{
    if(n<2) return 0;
    return (ll)(n-1)*n/2%mod;
}

int C_3(int n)
{
    if(n<3) return 0;
    return (ll)(n)*(n-1)*(n-2)/6%mod;
}

int main()
{  
    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        memset(cnt,0,sizeof cnt);
        for(int i=1;i<=n;i++) 
        {
            scanf("%d",&w[i]);p[i]=i;
            if(w[i]==1) {p1[i]=1, p2[i]=0;cnt[1]++;}
            else {p2[i]=1, p1[i]=0;cnt[2]++;}
        }
        int ans=(C_3(cnt[2])+(ll)C_2(cnt[2])*cnt[1]%mod)%mod;
        printf("%d\n",ans);
        
        int u,v;
        for(int i=0;i<n-1;i++)
        {
            int k=0;
            scanf("%d%d",&u,&v);
            int pu=Find(u), pv=Find(v);

            k=(k+(ll)p1[pu]*p2[pv]*(cnt[2]-p2[pu]-p2[pv]))%mod;
    
            k=(k+(ll)p2[pu]*p1[pv]*(cnt[2]-p2[pu]-p2[pv]))%mod;
            
            k=(k+(ll)p2[pu]*p2[pv]*(cnt[2]-p2[pu]-p2[pv]))%mod;
            
            k=(k+(ll)p2[pu]*p2[pv]*(cnt[1]-p1[pu]-p1[pv]))%mod;
            
            ans=(ans-k+mod)%mod;
            printf("%d\n",ans);
            p[pv]=pu;
            p1[pu]+=p1[pv], p2[pu]+=p2[pv];
            p1[pv]=0, p2[pv]=0;
        }
    }
    
    return 0;
}

1009 Parentheses Matching

题目:

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

题意

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

题解

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

代码

#include
#include
#include
#include
#include
#include
#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);   // ¶áèë¸ÕD′μÄÎļt
//    freopen("1009zhz.out", "w", stdout);  // êä3ö½«òaêä3öμÄêy¾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;
}

你可能感兴趣的:(补题库)