Educational Codeforces Round 157 1895C- Torn Lucky Ticket (div2 前缀和/思维 补)

题目链接: 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(1silength5)
定义幸运门票为:

  • 长度均匀
  • 前半部分的数字之和等于后半部分的数字之和。

您将获得 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) (1i,jn) 使得 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 n2105 普通暴力枚举 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(1isilength) 和 从 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=2sjlengthsilength,sum=2sjsumsisum) 。此时 时间复杂度为 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值