2020牛客暑期多校训练营(二) A.All with Pairs

这A感觉挺水的啊,为什么没什么人写(怕是大家都自闭了。

首先计算所有字符串每个后缀的hash值,记录每个hash值的出现次数。

对于每个字符串的每个前缀,我们记录与其hash值相同的后缀个数,但由于我们只对最长的符合要求的前缀计数,我们还要对该个数进行筛选。

假设我们的后缀集中有2个a,2个aba,1个ababa,我们对ababa进行匹配,前缀a能与a,aba,ababa匹配,共出现5次,同理aba出现3次,ababa出现1次。不难发现,若s_{1...i}=t_{|t|-i+1...|t|},因为s_{1...next[i]}=s_{i-next[i]+1...i},所以\dpi{150} s_{1...next[i]} = t_{|t|-next[i]+1...|t|}。同理\dpi{150} s_{1...next[next[i]]} = t_{|t|-next[next[i]]+1...|t|}...

所以我们只须做一遍从前到后做一遍cntpre[next[i]] -= cntpre[i]即可排除重复情况(cntpre[i]为前缀1~i出现的次数)

#include<bits/stdc++.h>

using namespace std;
#define lowbit(x) ((x)&(-x))
#define REP(i, a, n) for(int i=a;i<=(n);i++)
#define IOS ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;

const int maxn = 1e5 + 10;
const int N = 1e6 + 10;
const int M = 1e3 + 10;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const int mod2 = 998244353;
const int mod3 = 1e9 + 9;
const int hash1 = 131;
const int hash2 = 13331;
const double eps = 1e-6;
unordered_map<ull, int> cnt;
ull p[N], f[N];
string a[N];
int nxt[N];

void getnext(string &a)
{
    int len = a.length();
    nxt[1] = 0;
    for (int i = 2, j = 0; i < len; i++)
    {
        while (j && a[i] != a[j + 1])
            j = nxt[j];
        if (a[j + 1] == a[i])
            j++;
        nxt[i] = j;
    }
}

void prework(string &a)
{
    ull val = 0;
    int t = 0;
    for (int i = a.length() - 1; i >= 1; i--)
    {
        val = val + (a[i] - 'a' + 1) * p[t++];
        cnt[val]++;
    }

}

int cntpre[N];
ll ans;

void work(string &a)
{
    getnext(a);
    ull val = 0;
    for (int i = 1; i <= a.length() - 1; i++)
    {
        val = val * hash1 + a[i] - 'a' + 1;
        cntpre[i] = cnt[val];
    }
    for (int i = 1; i <= a.length() - 1; i++)
    {
        cntpre[nxt[i]] -= cntpre[i];
    }
    for (int i = 1; i <= a.length() - 1; i++)
    {
        ans += (ll) i * i * cntpre[i];
        ans %= mod2;
    }
}

int main()
{
    IOS;
    int n;
    cin >> n;
    p[0] = 1;
    for (int i = 1; i < N; i++)
    {
        p[i] = p[i - 1] * hash1;
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        a[i] = "@" + a[i];
        prework(a[i]);
    }
    for (int i = 1; i <= n; i++)
    {
        work(a[i]);
    }
    cout << ans << endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值