2019.10.24模拟赛

T1 古代龙人的谜题

Mark Douglas 是一名调查员。他接受了「调查古代龙人」的任务。经过千辛万苦,Mark 终于找到了一位古代龙人。Mark 找到他时,他正在摆弄一些秘药,其中一些药丸由于是从很久以前流传下来的,发出了独特的光泽。古代龙人告诉了 Mark 一些他想知道的事情,看了看手中的秘药,决定考一考这位来访者。
古代龙人手中共有\(n\)粒秘药,我们可以用\(1\)表示「古老的秘药」,其余的用\(0\)表示。他将它们排成一列。古代龙人认为平衡是美的,于是他问 Mark 能选出多少个「平衡的区间」。「平衡的区间」是指首先选出一个区间\([L,R]\),在它内部选出一个中间点\(mid\),满足\(L < mid < R\),\(mid\)是「古老的秘药」,且区间\([L,R]\)\([mid,R]\)中「古老的秘药」个数相等。

SOV

可行的区间一定有奇数个1,考虑统计1的贡献。
先记录每个一1右侧的0的个数,之后分奇偶求和。
奇数1都可以和奇数1配对,偶数1都可以和偶数1配对,对答案产生贡献。
每个单独的1单独计算答案即可。

int main() {
    int Case;
    register int n, m = 0;
    register long long ans = 0;
    poread(Case);
    poread(n);
    for (register int i = 1; i <= n; ++i) a[i] = g(), m += a[i];
    for (register int i = n, j = m, sum = 0; i && j; --i) a[i] ? ++sum, cnt[j] = sum, sum = 0, --j : ++sum;
    register long long lr[2] = { 0, 0 };
    for (register int i = 1; i <= m; ++i) lr[i & 1] += cnt[i];
    for (register int i = 1, sum = 0, j = 1; i <= n; ++i)
        a[i] ? ++sum, lr[j & 1] -= cnt[j], ans += (long long)(sum - 1) * (cnt[j] - 1) + sum * lr[j & 1],
            sum = 0, ++j : ++sum;
    printf("%lld", ans);
}

T2 交错的字符串

Mark Douglas 是一名律师。他的客户 Yuri Ball 在一场车祸中不幸去世。为了帮助 Yuri 的亲属拿到他的遗产, Mark 需要得到一个密码。在 Yuri 的笔记本上,有一个长为 的只包含小写字母的字符串, Mark 知道密码恰好是将这个字符串分解为两个长度为\(n\)的子序列且它们构成的字符串恰好相反的方案数。我们认为两种分解方法是不同的,当且仅当两个下标集合构成的集合$ {S1,S2}\(是不同的,注意\) {S1,S2}$ 和 $ {S2,S1}$ 我们认为是相同的分解方法。如 cabaacba 的合法分解共有 cabaacba 和 cabaacba 两种。 Mark 希望你能帮助他计算出密码,事成之后他决定分给你 six million five hundred thousand dollars 并邀请你去柬埔寨度假。

SOV

折半搜索。
搜索左半可以分成的,放到\(hash\)记录,搜索右半部分记录答案。

#include <bits/stdc++.h>
using namespace std;
short n;
long long ans;
char s[38];
unordered_map<string, long long> mp;
bool v[38];
inline void dfs1(short now) {
    if (now == n + 1) {
        string s1, s2;
        for (register int i = 1; i <= n; ++i)
            if (v[i])
                s1 += s[i];
        for (register int i = n; i; --i)
            if (!v[i])
                s2 += s[i];
        ++mp[s1 + '|' + s2];
        return;
    }
    v[now] = 0;
    dfs1(now + 1);
    v[now] = 1;
    dfs1(now + 1);
}
inline void dfs2(short now) {
    if (now == 2 * n + 1) {
        string s1, s2;
        for (register int i = n + 1; i <= 2 * n; ++i)
            if (v[i])
                s1 += s[i];
        for (register int i = 2 * n; i > n; --i)
            if (!v[i])
                s2 += s[i];
        ans += mp[s2 + '|' + s1];
        return;
    }
    v[now] = 0;
    dfs2(now + 1);
    v[now] = 1;
    dfs2(now + 1);
}
int main() {
    cin >> n;
    cin >> s + 1;
    dfs1(1);
    dfs2(n + 1);
    cout << ans / 2 << endl;
}

猜你喜欢

转载自www.cnblogs.com/Shiina-Rikka/p/11745198.html