zoukankan      html  css  js  c++  java
  • 相同字符串问题_题解

    题目:相同字符串问题

    题目描述

    N张写有字符串的卡片,已知第i张卡片上的字符串长度为Ai。某人两次从N张卡片中随机抽取K1,K2张卡片,方法如下:其随意抽出一张卡片,并记下卡上的字符串,再将卡放回原处,这样抽出Ki张卡后,将每次抽出的字符串顺序排列起来,就得到一个长度为Ki次抽取的字符串总长的新字符串。
    如果我们把每张卡片上的字符串都用规定长度的小写英文字符串来表示,该人两次抽取得到的新字符串相等,那么我们就称这些小写英文字符串为方程的一个解。
    编程任务:给定N张卡片、各卡上的字符串长,及该人两次抽出的卡片编号,求使两次抽取所得字符串相等的方案数。
    输入格式

    第一行有三个整数N,K1,K2,0<N<=50。接下来的一行有N个整数Ai。第三行有K1个整数,为第一次抽取的卡片编号。第四行K2个整数,为第二次抽取的卡片编号。
    输出格式

    输出满足条件的方案数。

    样例

    样例输入1

    3  2  2
    1  1  1
    1  2
    1  3
    

    样例输出1

    676
    

    分析

    这个题目描述非常难看懂……

    我用下面这个数据解释一下吧。

    3 2 2
    1 2 1
    1 3 1 3
    2 2
    

    (3)张卡片,(a_1=1,a_2=2,a_3=1),一共(4)个字母。给每个单个的字母编号,用(g[i])存第(i)张卡片的字符(动态数组vector):

    [g[1]={1},g[2]={2,3},g[3]={4} ]

    那么(k_1)就是(1,4,1,4)字母序列,(k_2)(2,3,2,3)序列。

    这两个序列要对应相等,也就是序号为(1)的字母要等于序号为(2)的字母,相同的,(字母4=字母3)

    这样可以得到一些相等的字母。把一堆相等的字母放到一个集合中,一共有(root)个彼此分离的集合,那么方案数就是(26^{root})

    于是可以用并查集做,注意数据范围(题目好像没说清楚,但反正很大,都26的乘方了),要高精度。

    参考代码(cpp)

    #include<cstdio>
    #include<vector>
    #include<cstring>
    using namespace std;
    int n,k1,k2,na=0,nb=0;
    vector<int> g[51];
    int a[10000],b[10000],par[10000],root;
    struct hp{
        int len,s[1000];
    };
    void init(){
        int ai,ki,k=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&ai);
            g[i].clear();
            for(int j=1;j<=ai;j++) g[i].push_back(++k);
        }
        n=k; root=n;
        for(int i=1;i<=k1;i++){
            scanf("%d",&ki);
            for(int j=0;j<g[ki].size();j++) a[++na]=g[ki][j];
        }
        for(int i=1;i<=k2;i++){
            scanf("%d",&ki);
            for(int j=0;j<g[ki].size();j++) b[++nb]=g[ki][j];
        }
        for(int i=1;i<=n;i++) par[i]=i;
    }
    int find(int x){
        if(par[x]==x) return x;
        else return par[x]=find(par[x]);
    }
    void unite(int x,int y){
        x=find(x);
        y=find(y);
        if(x==y) return;
        if(x<y) par[y]=x;
        else par[x]=y;
        --root;
    }
    void mult(hp a,int b,hp &c){
        int len=a.len;
        memset(c.s,0,sizeof(c.s));
        for(int i=0;i<len;i++){
            c.s[i]=c.s[i]+a.s[i]*b;
            c.s[i+1]+=c.s[i]/10;
            c.s[i]=c.s[i]%10;
        }
        while(c.s[len]>=10){
            c.s[len+1]+=c.s[len]/10;
            c.s[len]=c.s[len]%10;
            len++;
        }
        len++;
        while(len>1&&c.s[len-1]==0) len--;
        c.len=len;
    }
    int main(){
        int m=0; hp ans;
        scanf("%d%d%d",&n,&k1,&k2);
        init();
        if(na!=nb) {printf("0
    "); return 0;}
        ans.len=1; ans.s[0]=1;
        for(int i=1;i<=n;i++) unite(a[i],b[i]);
        for(int i=1;i<=root;i++) mult(ans,26,ans);
        for(int i=ans.len-1;i>=0;i--) printf("%d",ans.s[i]);
        return 0;
    }
    
  • 相关阅读:
    最简单的图片轮播
    首页图片轮播效果
    windows简单杀死进程的批处理程序
    js实现无限级树形导航列表
    漂亮竖向菜单 有缓存 javascript
    竖向折叠二级导航JS代码(可防刷新ul/li结构)
    bzoj 1060: [ZJOI2007]时态同步【树形dp】
    bzoj 2733: [HNOI2012]永无乡【并查集+权值线段树】
    洛谷 P3952 时间复杂度【模拟】
    bzoj 2208: [Jsoi2010]连通数【tarjan+拓扑+dp】
  • 原文地址:https://www.cnblogs.com/1024th/p/10540378.html
Copyright © 2011-2022 走看看