相同字符串问题_题解

题目:相同字符串问题

题目描述

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\n"); 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;
}
posted @ 2019-03-16 00:21  樱花赞  阅读(441)  评论(0编辑  收藏  举报