CCUT应用OJ——小龙的字符串函数
题目简介
- 题源:1073 - 小龙的字符串函数 | CCUT OJ
- 题意:给定 \(n\) 个等长字符串,定义函数 \(f(s_i,s_j)\) 表示字符串 \(s_i\) 与 \(s_j\) 中位置和字符相同的总数。输出 \(\sum f(s_i,s_j)\) ( 其中 \(i<j\) )。
- 数据范围:\(1\le n\le 2000,1\le |s_i|\le 2000\)
- 注:若无特殊说明,博主的代码模板如下,通过
solve函数处理多组测试用例。本文后续代码仅给出solve函数。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define ln '\n'
int solve(){
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
int T;cin>>T;
while(T--){
cout<<solve()<<ln;
}
return 0;
}
朴素想法
朴素想法极其简单,双循环两两遍历字符串,逐位检查是否相同即可。复杂度 \(O(n^2 \cdot |s_i|)\),超时。
int solve(){
int n;cin >> n;
vector<string> strs(n);
for (auto &i:strs) cin >> i;
int L = strs[0].size();
i64 ans = 0;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
for (int k = 0; k < L; k++)
if (strs[i][k] == strs[j][k])
ans++;
return ans;
}
题解
定义权值数组 cnt[i][26],表示这些字符串第 \(i\) 位上各字母出现的频率。根据排列组合知识,假设字符 \(j\) 在第 \(i\) 位上出现了 cnt[i][j] 次,则其在该位上可两两配对的次数为\(C_{cnt[i][j]}^2=\dfrac{cnt[i][j]\cdot (cnt[i][j]-1)}{2}\) 次。时间复杂度 \(O(n \cdot|s_i|\cdot 26)\)。
int solve() {
int n; cin >> n;
vector<string> strs(n);
for (auto &i:strs) cin >> i;
int L = strs[0].size();
int cnt[2000][26] = {0};
for (int k = 0; k < n; k++)
for (int i = 0; i < L; i++)
cnt[i][strs[k][i]-'a']++;
i64 ans = 0;
for (int i = 0; i < L; i++)
for (int j = 0; j < 26; j++)
ans += 1LL * cnt[i][j] * (cnt[i][j]-1) / 2;
return ans;
}

浙公网安备 33010602011771号