CCUT应用OJ——小龙的字符串函数
题目简介
- 题源:1073 - 小龙的字符串函数 | CCUT OJ
- 题意:给定 nnn 个等长字符串,定义函数 f(si,sj)f(s_i,s_j)f(si,sj) 表示字符串 sis_isi 与 sjs_jsj 中位置和字符相同的总数。输出 ∑f(si,sj)\sum f(s_i,s_j)∑f(si,sj) ( 其中 i<ji<ji<j )。
- 数据范围:1≤n≤2000,1≤∣si∣≤20001\le n\le 2000,1\le |s_i|\le 20001≤n≤2000,1≤∣si∣≤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(n2⋅∣si∣)O(n^2 \cdot |s_i|)O(n2⋅∣si∣),超时。
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],表示这些字符串第 iii 位上各字母出现的频率。根据排列组合知识,假设字符 jjj 在第 iii 位上出现了 cnt[i][j] 次,则其在该位上可两两配对的次数为Ccnt[i][j]2=cnt[i][j]⋅(cnt[i][j]−1)2C_{cnt[i][j]}^2=\dfrac{cnt[i][j]\cdot (cnt[i][j]-1)}{2}Ccnt[i][j]2=2cnt[i][j]⋅(cnt[i][j]−1) 次。时间复杂度 O(n⋅∣si∣⋅26)O(n \cdot|s_i|\cdot 26)O(n⋅∣si∣⋅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;
}
