字符串工厂

字符串工厂

定义两个字符串间的相似程度,为两个字符串中所有字符对(包括重复)的相似程度的和。字符对的相似程度已经给出。例如,\(s[‘a’][‘a’]=s[‘b’][‘b’]=s[‘c’][‘c’]=2,s[‘a’][‘b’]=s[‘a’][‘c’]=1,s[‘b’][‘c’]=0\)。则字符串”ab”与字符串”caa”的相似度为\(s[‘a’][‘c’]+s[‘a’][‘a’]+s[‘a’][‘a’]+s[‘b’][‘c’]+s[‘b’][‘a’]+s[‘b’][‘a’]=1+2+2+0+1+1=7\) 。现在给你n个字符串,求出它们两两之间的相似度之和\(g(s1,s1)+g(s1,s2)+…g(s1,sn)+g(s2,s2)+g(s2,s3)+…+g(s2,sn)+…+g(sn,sn)\),求出他们两两之间的相似度的平方和\(g(s1,s1)^2+g(s1,s2)^2+…g(s1,sn)^2+g(s2,s2)^2+g(s2,s3)^2+…+g(s2,sn)^2+…+g(sn,sn))^2\)。字符包括大小写字母或阿拉伯数字。\(n<=1000,s[i][j]<=1000,字符串总长度S<=10^6\)

最暴力的枚举是\(O(n^2Si^2)\)的,有20分。稍微不那么暴力一点的做法是预处理出每一个字符串,其中的每一种字符的个数,然后\(O(n^2)\)枚举字符串,\(O(62^2)\)求解,时间复杂度\(O(n^262^2)\),能拿40分。满分做法是首先\(O(S)\),预处理出每个字符串中每一种字符的个数,然后用\(O(62^2n)\)的时间,求出一个字符对于一个字符串的相似度,最后用\(O(62n^2)\)的时间,枚举一对字符串s1,s2,并算出s1中每种字符对于s2的相似度,然后把它们加起来,累加到答案中。于是正解是\(O(S+62^2n+62n^2)\),就过了。

#include <cctype>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const int maxn=1e3+5, maxc=70, maxl=1e6+5, mod=1e9+7;
int n, m, len, map[maxc][maxc], l[maxn];
char* s[maxn]; char tmp[maxl];
//c:字符串中出现的每种字符的数量 like:一个字符和字符串的相似度
int c[maxn][62], like[maxn][62];
LL ans1, ans2;

inline int convert(char c){
    if (c>='0'&&c<='9') return c-'0';
    if (c>='A'&&c<='Z') return 10+c-'A';
    if (c>='a'&&c<='z') return 36+c-'a';
    return -1;
}

inline char rc(){
    char re;
    for (re=getchar(); !isgraph(re); re=getchar());
    return re;
}

inline char* rs(){
    scanf("%s", tmp); len=strlen(tmp);
    char *re=new char[len+1];
    memset(re, 0, len+1);
    for (int i=0; i<=len; ++i) re[i]=tmp[i];
    return re;
}

int main(){
    scanf("%d%d", &n, &m);
    char x, y; int w, t1, t2; LL tmp;
    for (int i=0; i<m; ++i){
        x=rc(); y=rc(); scanf("%d", &w);
        t1=convert(x); t2=convert(y);
        map[t1][t2]=map[t2][t1]=w;
    }
    for (int i=0; i<n; ++i){
        s[i]=rs(); l[i]=strlen(s[i]);
        for (int j=0; j<l[i]; ++j)
            ++c[i][convert(s[i][j])];
        for (int j=0; j<62; ++j)
            for (int k=0; k<62; ++k)
                like[i][j]+=c[i][k]*map[j][k];
    }
    for (int i=0; i<n; ++i)
        for (int j=0; j<=i; ++j){
            tmp=0;
            for (int k=0; k<62; ++k)
                tmp+=LL(c[j][k])*like[i][k];
            ans1=(ans1+tmp)%mod; ans2=(ans2+tmp*tmp)%mod;
        }
    printf("%lld\n%lld\n", ans1, ans2);
    return 0;
}
posted @ 2017-11-02 20:30  pechpo  阅读(207)  评论(0编辑  收藏  举报