题目链接: https://codeforces.com/contest/1895/problem/C
题目大意:
门票是从
1
1
1 到
9
9
9 的非空数字字符串
s
i
(
1
≤
s
i
l
e
n
g
t
h
≤
5
)
s_i (1≤s_ilength ≤5)
si(1≤silength≤5)。
定义幸运门票为:
- 长度均匀
- 前半部分的数字之和等于后半部分的数字之和。
您将获得 n n n 张门票 s 1 , s 2 , s 3 , … , s n s_1,s_2,s_3,…,s_n s1,s2,s3,…,sn。请问有多少对 ( i , j ) (i,j) (i,j) ( 1 ≤ i , j ≤ n ) (1≤i,j≤n) (1≤i,j≤n) 使得 s i + s j ( e g . s i = 13 , s j = 37 , s i + s j = 1337 ) s_i+s_j(eg. s_i=13,s_j=37,s_i+s_j=1337) si+sj(eg.si=13,sj=37,si+sj=1337) 是一张幸运门票?请注意可能 ( i = = j ) (i ==j) (i==j) 。
题目思路:
首先注意到 n ≤ 2 ∗ 1 0 5 n≤2*10^5 n≤2∗105 普通暴力枚举 O ( n 2 ) O(n^2) O(n2) 肯定超时。不难发现只要利用前缀和记录 s i s_i si 到每个位置的数字之和,然后记录 c n t [ s i l e n g t h ] [ s i s u m ] cnt[s_ilength][s_isum] cnt[silength][sisum] ,然后枚举每个 s i s_i si 从 1 1 1 到 i ( 1 ≤ i ≤ s i l e n g t h ) i(1≤i≤s_ilength) i(1≤i≤silength) 和 从 i i i 到 s i l e n g t h s_ilength silength 的数字之和 所对应需要的 c n t [ l e n g t h ] [ s u m ] cnt[length][sum] cnt[length][sum] 是否存在。其中 ( l e n g t h = 2 ∗ s j l e n g t h − s i l e n g t h , s u m = 2 ∗ s j s u m − s i s u m ) (length=2*s_jlength - s_ilength , sum=2*s_jsum - s_isum) (length=2∗sjlength−silength,sum=2∗sjsum−sisum) 。此时 时间复杂度为 O ( n ) O(n) O(n) 。
题目代码:
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5+10;
int n, ans = 0;
int sum[N][7], cnt[10][N];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++) {
string s;
cin >> s;
int len = s.size();
for (int j = 0; j < len; j++) {
sum[i][j + 1] = sum[i][j] + s[j] - '0';
}
sum[i][0] = len;
int total = sum[i][len];
cnt[len][total]++;
}
ans = 0;
for (int i = 1; i <= n; i++) {
int len = sum[i][0];
int total = sum[i][len];
ans += cnt[len][total];
for (int j = 1; j < len; j++) {
if (2 * j <= len)
continue;
ans += cnt[2 * j - len][2 * sum[i][j] - total];
ans += cnt[2 * j - len][2 * (sum[i][len] - sum[i][len - j]) - total];
}
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
// cout.tie(0);
// int _;cin>>_;
// while(_--)
solve();
return 0;
}