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;
}

原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11745198.html

时间: 2024-11-05 23:36:51

2019.10.24模拟赛的相关文章

2019.10.24模拟赛赛后总结

本文原创,如果有不到位的地方欢迎通过右下角的按钮私信我! A.Icow Player 题目描述 被无止境的农活压榨得筋疲力尽后,Farmer John打算用他在MP3播放器市场新买的iCow来听些音乐,放松一下.FJ的iCow里存了N(1 <= N <= 1,000)首曲子,按1..N依次编号.至于曲子播放的顺序,则是按一个Farmer John自己设计的算法来决定: * 第i首曲子有一个初始权值R_i(1 <= R_i <= 10,000). * 当一首曲子播放完毕,接下来播放的

2019.10.18模拟赛T3

题目大意: 求$\sum\limits_{i=1}^n\sum\limits_{j=1}^n[lcm(i,j)>n](n\leq 10^{10})$的值. 题解: 这题貌似有n多种做法... 为了更好统计,把原式变为$n^2-\sum\limits_{i=1}^n\sum\limits_{j=1}^n[lcm(i,j)\leq n]$. 然后开始毒瘤... 首先,考虑枚举$lcm(i,j)$,设为$d$,计算有多少对$i.j$的最小公倍数为$d$. 设$i=p_1^{a_1}p_2^{a_2}\

2019.10.26模拟赛

T1 序列 给定一长度为\(n\)的序列\(s\),定义其健美值为:\[\sum\limits_{i=1}^{n}|s_i - i|\]因为 zzq 喜欢健美,所以 zzq 希望减小\(s\)的健美值,以衬托 zzq 的健美.为了达到 zzq 的目的,zzq 希望你对序列进行旋转操作,一次旋转操作可以使序列中的所有元素前移一位,并使\(s_1\)移动到\(s_n\). 可以进行任意次旋转操作,zzq 希望旋转后的健美值最小,请找出这个最小值. SOV 智商检测题 我们发现对于每个数,移动每一次会

2019.10.22模拟赛

T1 合并集合 有\(n\)个集合,第\(i\)个集合记为\(S_i\),集合按环状排列,即第\(i + 1\)个集合右边是第\(i\)个集合,第\(n\)个集合右边是第\(i\)个集合. 一开始每个集合里只有一个数,每次你可以选择两个相邻的集合\(S,T\),然后合并成\(S \cup T\),之后你可以获得收益\(|S| \times |T|\),其中\(|S|\)表示集合\(S\)的元素个数. 你需要一直进行以上的操作直到只剩一个集合为止,求能获得的最大的收益之和. 断环为链,复制两倍区间

2019.10.31模拟赛

说在前面 考场遇见原题??? 上午刚做的 下午就\(T3\)考到了\(2333\) 然而还是因为忘了取模挂了28分 T1 Dove下跳棋 数据太水输出n-1可得90 Dove 喜爱下跳棋,在传统的跳棋基础之上,Dove 又延伸出了许多别的玩法.Dove 以一个一维数轴为棋盘下跳棋,总共会移动棋子?? ? 1 次.因为讨厌没有规律,所以Dove 每次只会恰好把棋子向右移动?? 个格子. Cicada 送给了Dove 一个长度为?? 的数列{??},为了表示感谢,Dove 打算以Cicada 送给他

10.2模拟赛总结

10.2 模拟赛总结 T1. 数位dp: 一个非常非常非常非常显然的数位 DP \([L,R] = [1,R]-[1,L-1]\) 所以是分别求两次小于等于某个数字的方案数 \(f(i,j,k)\) 表示从低位数起的第 \(i\) 位,按照规则计算后答案为 \(j\quad (j=0,1)\) \(k\) 表示只考虑后面结尾和 \(lmt\)后面几位 的大小关系 \((k=0,1)\) 考虑第 \(i+1\) 位,算一下新构成的数字并判断下大小就可以了 注意到 \(L,R\) 数据范围特别大,需

10.22 模拟赛

10.22 模拟赛 T1 染色 考虑每个连通块删成一棵树就好了. mmp场上就我路径压缩写炸.... #include<iostream> #define MAXN 200006 using namespace std; int n , m; int fa[MAXN] , siz[MAXN] , book[MAXN] , sz[MAXN]; int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } int main() {

10.31 模拟赛

10.31 模拟赛 A LIS 考虑每个数字前从 $ m $ 降序构造到 $ a_i $ 即可. #include <iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<vector> using namespace std; #define MAXN 300006 int n , m , k; int A[MAXN]; vector<int&g

2018/5/24模拟赛总结

shzr带病AK虐爆全场... T1n皇后: 这题没啥好说的... T2有重复元素的排列问题: [问题描述] 设R={ r1, r2 , -, rn}是要进行排列的n个元素.其中元素r1, r2 , -, rn可能相同.试设计一个算法,列出R的所有不同排列. [编程任务] 给定n 以及待排列的n 个元素.计算出这n 个元素的所有不同排列. [输入格式] 由perm.in输入数据.文件的第1 行是元素个数n,1≤n≤500.接下来的1 行是待排列的n个元素. [输出格式] 计算出的n个元素的所有不