10.12至10.14考试题

10.12

NOIp信心赛(QBXT Day2)

NOIp信心赛

为什么这个p是小写的?

异或

【问题描述】

给定序列A,计算\(\displaystyle\sum_{i=1}^n\sum_{j=1}^n{A_i\mathrm{and}A_{i+1}\mathrm{and}\dots\mathrm{and}A_j}\)

【输入格式】

从文件 a.in 中读入数据。

第一行一个整数N。

第二行N个整数描述A。

【输出格式】

输出到文件a.out中。

一行输出答案。

【样例输入】

3
1 2 3

【样例输出】

8

【样例解释】

1+2+3+0[1~2]+2[2~3]+0[1~3]=8

【数据规模】

对于10%的数据,\(N\le100,A_i\le1\)

对于20%的数据,\(N\le100\)

对于30%的数据,\(N\le1000\)

对于40%的数据,\(N\le100000\)

以上的数据档互不相交。

对于所有的数据,满足\(1\le N\le10^5,0\le A_i\le2^{31}-1\)

【题解】

二进制位是互不相干的,所以可以拆位处理。

一个区间有贡献,当且仅当区间内没有0。

所以可以处理出所有全为1的极长的区间,区间内贡献即为n(n+1)/2。注意每一位要乘以它的掩码。

细胞分裂

【问题描述】
你正在一个长度为N的环状台上进行细胞分裂的实验。

这个试验台一共有N个格子,每个格子被标号为0..N-1,其中1格子与i-1和i+1号格子相邻。值得注意的是,当i=0时,i−1视为N−1,同理i=N−1时,i+1视为0。一开始,在某些格子上可能会有1个细胞,也可能没有。

在每一秒钟的末尾,每一个细胞会分裂成2个细胞,并且一个到达i-1位置,一个到达i+1位置。

现在已知最开始的细胞存在情况,假设第一个时刻末开始第一次分裂,求第T个时刻末分裂结束后每个格子的细胞个数。

为了方便你只需要输出每个格子的细胞数量对P取模的值。

【输入格式】

从文件b.in中读入数据。

第一行三个整数N,T,P,分别表示环的长度,时刻和模数。

第二行一个01串s描述这个串。

【输出格式】

输出到文件b.out中。

N行,第i行输出编号为i-1的格子的答案。

【样例输入】

5 2 2
00100

【样例输出】

1
0
0
0
1

【样例解释】

一开始每个格子的个数为0 0 1 0 0
在第一个时刻变为0 1 0 1 0
在第二个时刻变为1 0 2 0 1

【数据规模】

对于30%的数据,N,T≤1000.

对于20%的数据,N≤18,P=2

对于10%的数据,P=2,T=402653184.

对于10%的数据,P=2

对于30%的数据,没有任何限制。

以上数据档互不相交

所有数据满足:1≤N≤100000, 0≤T≤10^9,2≤P≤ 10,且P一定是质数.

【题解】

本来以为是矩阵快速幂板子题,结果一看数据范围,连多项式取模都过不了。

反正是一个特别奇怪的规律

待更

递归

【问题描述】

ZYB是一个非常强大的ACM手,他与别人交流的方式也与众不同-利用数字串,并且他将对这个数字串进行加密处理。

这个加密处理的方式如下:

信息中会涉及到前K种大写字符以及所有的数字,并且对于每一个大写字母,有一个唯一的替换串。

例如A->BB,B->CC0,C->123都是合法的替换串,分别表示A=12312301231230,B=1231230,C=123.

现在ZYB告诉了你一个大写字母A。辣鸡出题人立刻就破解出了他的原文,但是辣鸡出题人还想知道,对于这个数字串,有多少非空的子串满足:

1.这个子串为0或者没有前导0.

2.把这个子串看作10进制数后模n为0.

你只需要输出合法的子串个数模r的值。

【输入格式】

从文件c.in中读取数据。

第一行,两个正整数n,r.

第二行,一个正整数k.

接下来k行,每行一个替换式\(S_i\)。保证按照A,B...的顺序给出。并且字符X的替换串中只会出现比X大的字符。

【输出格式】

输出到文件 c.out 中。

一行一个整数,输出答案。

【数据规模】

对于20%的数据,最终串的长度不超过150.

对于30%的数据,最终串的长度不超过100000.

对于20%的数据,没有0字符。

对于30%的数据,没有任何限制。

以上数据档互不包含。

对于100%的数据,\(2\le n\le 30,2\le r\le 10^9,1\le k\le 26,4\le |S_i|\le100\)

【题解】

贼他妈复杂的一道题。

考虑维护一个区间的信息。

因为本题在组成一个替换的过程,可以视为合并若干个区间的过程,所以我们维护的信息要求能够方便合并。

对于维护下列信息:

contribution 区间内的串的贡献
len 10的[区间长度]次方对n取模
tot 区间代表数对n取模
head[i][j] 满足10的[长度]次方对n取模为i,代表数对n取模为j的前缀的个数
tail[i] 满足代表数对n取模为j的后缀的个数

对于合并区间,即给定两个区间a和b的信息,需要计算ans的信息的操作,我们:

对于len:ans.len=(a.len*b.len)%n,根据初中课本,同底数幂的乘法底数不变指数相加,反过来即可。

对于tot:ans.tot=(a.tot*b.len+b.tot)%n。把两个数合并就相当于前面的数左移后面数的位数,再相加(十进制下的左移就是乘以10)

对于contribution:根据cdq分治的思想,ans的贡献就是a的贡献加b的贡献加跨过a和b中间点区间的贡献。

枚举a的后缀a.tail[k]和b的前缀b.head[i][j],如果这两部分接上之后模n为0,即(k*i+j)%n=0,那么就对答案禅城a.tail[k]*b.head[i][j]的贡献。

对于head:显然ans的head是由两部分组成,第一部分是a的前缀,第二部分是由整个a区间和b的前缀组成的前缀。第一部分直接从a的head那里copy一下即可,第二部分就要枚举b的head,转移如下:ans.head[(i*a.len)%n][(a.tot*i+j)%n]+=b.head[i][j]

对于tail:同上,ans的tail也是两部分组成,第一部分是b的后缀,第二部分是有整个b区间和a的后缀组成的后缀。第一部分同上直接copy,第二部分也推一下式子:ans.tail[(i*b.len+b.tot)%n]+=a.tail[i]

这样我们的区间合并就完成了。然后我们先处理出所有只包含一个数字的区间(注意0不能做一个区间的开头,其实是不能做一个后缀的开头,因为对答案的贡献形式只能是一个后缀和一个前缀)。我们把0的tail设为0,其它的设为1即可。head[10%n][num%n]可以都设为1。注意如果num%n=0那么这区间也有1的贡献。

然后从最大的字母开始计算这个字母缩代表的区间的信息,直接大力区间合并即可。复杂度期望O(sumS*n^3)

std的代码好像很简单的呢



10.13

zmj

canteen

背景

雷哥再也忍受不了吃不上饭的日子了,便自己靠武力智慧向主任申请开了一个自己的窗口,这样雷哥就不用去排队打饭,当然雷哥为了弘扬中华美德,也供其他的人来吃。因为饭菜好吃,来的人越来越多,排起了长队。当然,雷哥作为这个窗口的主人,一定要解决这个问题,他的解决方式很特殊,就是让妹子排在队伍的前面,这样更方便提高他在妹子面前的面子。即使这样,也有好多贪吃的男生来这里打饭并提出了意见,比如说wyl,他提的意见被雷哥全部否定,他一气之下说“别跟我扯”,又被雷哥治服了,从此男孩子只能乖乖的排在队伍后面。。。

题目描述

雷哥每次可以安排他的小弟去调换相邻两个人的位置,因为雷哥的小弟有无数个,所以每单位时间可以将任意相邻的两个人交换,妹子用'a'表示,汉子用'b'表示,问最短多少时间可以将所有的妹子都排在前面,(不懂的可以去看样例解释)。

输入

一行字符串(只包含'a','b')。

输出

一个整数t,表示最短时间。

输入样例#1

baba

输出样例#1

2

解释

baba--1-->abab--2-->aabb

输入样例2

baab

输出样例2

2

解释

baab--1-->abab--2-->aabb

数据点 字符串的长度 特殊性质
1 10
2 100
3 1000
4 5000
5~6 50000
7~10 1000000

题解

神仙题,用各种xjb推法都能退出来正确的结论。

首先不难想到一个贪心包丽丽:贪心地交换前面的b和后面的a。

我的思路是:把所有的b当做空格,就相当于让a一个劲往前走。例如:

      aaaa  a .
     a aaa a .
    a a aaa .
   a a a aa.
  a a a a a
 a a a a a
a a a a a
aa a a a
aaa a a
aaaa a
aaaaa

正常情况下是每个a每一秒向前走一格,但是最后一个a因为前面的a的限制,需要等待才可以走。一串稳定的a是这些a之间有一个空格。所以我们就可以让最后一个a一开始时候在.的位置,这样就保证他是匀速前进的。我们对于每一个a,按照每个a的间隔为1来计算最后一个a应当的的位置,并取max就行了。注意一开始就在原位的不用处理。

bobek

背景

终于到了假期,但是坐在沙发上看着电视,真是无聊。一会儿电话响了,是我的好朋友bobek的电话,“一起去看球吧”,“好啊,反正也是无聊”,“10分钟之内到XXX体育馆“,”没问题“。我便拉上睡懒觉的王小呆出发了。现场真是人山人海,队伍排了好长,谁知bobek有VIP,直接就可以买票,到了VIP售票口,面对种类繁多的门票,我们有犯了愁,不知道买哪些票。王小呆突然站出来,“让我来吧”,王小呆拿出随身携带的电脑,通过 找到了你(原来是请别人解决,真不要脸)。。。

题目描述

王小呆告诉你一共有N种票,并告诉你每种票的价钱\(w_i(w_i\le10^{16})\),和bobek所拥有的钱M。问你用M元钱,bobek有多少种购票方案(如果存在以其中一种方案观看某场比赛而另一种方案不观看,则认为这两种方案不同,不买票也算一种方案)。

输入格式

第一行,两个正整数N和M(\(1\le N\le40,1\le M\le10^{18}\)) ,表示买票的种数和 bobek所拥有的钱。

第二行, 个以空格分隔的正整数,均不超过\(10^{16}\),代表每场比赛门票的价格。

输出格式

一个整数表示方案数。

输入样例

5 1000
100 1500 500 500 1000

输出样例

8

样例解释

扫兴,不看球了,回家上洛谷透彻吧

  • 买一张100块的

  • 买一张500块(第三种票)的

  • 买一张500块(第四种票)的

  • 买一张100块的和500块(第三种票)的

  • 买一张100块的和500块(第四种票)的

  • 买两张500块的

  • 要的就是奢侈,买一张1000块的

一共8种

数据范围

数据分布 n m
4% 20 10^6
14% 20 10^18
26% 40 10^6
100% 40 10^18

注意:数据后来有更改,现在的百分比是人工数出来的,可能有误,但一定会有部分分(已测试过)。

题解

可以背包转移

正解是meet in the middle思想,我们把n个数分两半搜,把最后答案存在两个数组里,每次搜都是1048576不会超时。把第二个数组sort一下,每次对应第一个数组,在第二个数组里二分upper_bound即可。

这里rqj提供了一种更快的方法,我们维护两个队列光搜,并保证这两个队列是单调的。每次搜的时候,从两个队列取最小值,并把扩展出的不选放到一个队列里,选放到另一个队列里,这样保证队列是单调的,就能保证最后处理出的两个数组都是排好序的

既然两个数组都排好序了,那么我们就可以维护两个指针xjb乱指,就能线性求出结果了。

GXZlegend的博客里好像只有第一种解法诶

stone

背景

王小呆被自己的梦迷失了心智,走火入魔,小zager不能置之不管,便踏上了寻找王小呆的旅程,谁知王小呆为了不让任何人进入自己的梦中,设置了一个迷宫,而且他可以操纵这个迷宫,让来到这里的人民都迷失在迷宫了,成为王小呆的奴隶。。。。

描述

王小呆设置的迷宫非常奇特,有N个点,N-1条边,他可以对迷宫中的每个点发起M次操作,例如:让某个点出现一块“金刚碧·清醒石”( xjb起的名字),也可以让某个点的“金刚碧·清醒石”消失,还能发出“迷失之雾”。但小zager要想不迷失在王小呆的梦了,必须在王小呆发出“迷失之雾”时快速去收集所有的“金刚碧·清醒石”,但小zager不用自己去动手,因为他有一个小宠物enceladus,可以快速的收集“金刚碧·清醒石”,但必须保证你告诉enceladus所有“金刚碧·清醒石”所在的点连通所需的边集的总长度最小是多少,因为enceladus是不会走冤枉路的。

输入格式

第一行 一个数N ;接下来N-1行,每行3个整数u,v,w表示u和v之间有一条长度为w的双向边;

接下来 一个数 M;

接下来M 行(三种格式之一):

insert x :表示点x上出现了“金刚碧·清醒石”;

destroy x:表示点x上的“金刚碧·清醒石”被摧毁;

enceladus :你要告诉 当前所有“金刚碧·清醒石”所在的点连通所需的边集的总长度最小是多少

输出格式

对于每一个 enceladus操作都输出一个整数表示答案。

输入样例

6
1 2 3
2 3 4
4 5 2
1 4 6
4 6 7
9
insert 2
insert 4
enceladus
insert 5
enceladus
destroy 4
enceladus
insert 6
enceladus

输出样例

9
11
11
18

提示

第一次询问时(是一张图,懒得摆了)

数据范围

n m 特殊性质
10 10
100 100
1000 1000
10000 10000 一条链
20000 20000 菊花图
50000 50000
100000 100000
100000 100000
50000 50000
100000 100000

题解

这是一道结论题。我们求出每个点的dfn来。对于插入和删除操作,把这个点的dfn加到一个红黑树里,答案是中序遍历相邻的节点之间的路径长度和/2(包括首末节点)。注意要动态维护答案。

好吧好理解但是不太会证明啊。这是比较烦的一件事。

也不太难证明吧,这里试一下。就是考虑我们dfs的过程,dfs出来了一个dfn对不对,就是每个点访问的先后次序。如果我们按照set里面dfn的次序依次访问节点,路径就是dfs路径的一条子路径?不能叫子路径,大概就是一段段区间的和。这能保证不走多余的路。这样我们走出来了一条环,环/2就是树的边长度和。



10.14

qbxt-dll

sword

【题目描述】

小林和亮亮各有一把光剑, 长度分别为 a 和 b, 他们拿光剑进行比试。 每一回合, 长光剑会砍向短光剑, 砍完后, 短光剑完好无损, 而长光剑则被截成两段,被截去的长度恰好等于短光剑的长度。 若两把光剑长度相等, 则比试结束。 请问小林和亮亮将比试多少回合?

【输入格式】

第一行一个整数 T, 表示数据组数。

接下来 T 行每行两个正整数 a, b, 表示初始状态光剑的长度。

【输出格式】

每组数据输出一个整数, 表示能进行几个回合的比试。

【样例输入】

3
18
3 7
6 6

【样例输出】

7
4
0

【数据规模】

对于 40%的数据, 0 < a, b <= 1000, 1 <= T <= 20;

对于 100%的数据, 0 < a, b <= 10^18, 1 <= T <= 1000。

【题解】

不难写出一个递归暴力:

int fuck(int x, int y)
{
    if (x == y)
        return 0;
    if (x > y)
        return fuck(x - y, y);
    if (x < y)
        return fuck(x, y - x);
}

我们发现,对于x-y会一直减下去,直到减到(x-1)%y+1,不能减为止,而换为y减去剩下的那个数字。减法的次数为(x-1)/y。这有点像我们的欧几里得算法求gcd。所以写一个类似于欧几里得算法的东西:

int fuck(int x, int y)
{
    if (x == y)
        return 0;
    if (x > y)
        return fuck((x - 1) % y + 1, y) + (x - 1) / y;
    if (x < y)
        return fuck(y, (y - 1) % x + 1) + (y - 1) / x;
}

当然也可以写成辗转相除的性质。复杂度和欧几里得算法等同,是log的。注意开long long。

zero

【题目描述】

小林拥有 2 个集合, 亮亮拥有 3 个集合, 这五个集合大小相等, 且集合中包含的都是整数。 现在他们两个要进行心算比赛。 比赛的规则是, 将这五个集合放在一起, 谁能先从每个集合中各选一个数, 使得选出的五个数之和为 0, 谁就获得胜利。 由于这五个集合都不小, 而小林和亮亮事先并不知道是否能存在这样的五个数, 因此他们决定先把五个集合都交给你, 由你来编程判断是否存在符合条件的五个数。

【输入格式】

第一行一个整数 N, 表示集合的大小。

接下来五行每行 N 个整数, 表示这五个集合内的元素。

【输出格式】

如果能找到符合条件的五个数, 则输出“YES” , 否则输出“NO” 。

【样例输入】

31
-2 9
-1 2 1
-3 5 1
-1 7 6
-4 -1 -7

【样例输出】

YES

【数据规模】

对于 30%的数据, 1 <= N <= 20;

对于 50%的数据, 1 <= N <= 100;

对于 100%的数据, 1 <= N <= 200, -10^8 <= a[i] <= 10^8, a[i]为集合中元素。

【题解】

由于直接搜索肯定会TLE,所以我们考虑双向搜索(其实直接for循环就行了),把前两组集合捆成一坨,后三组捆成一坨,前两组搜完了把所有结果存到一个哈希表中,搜后三组直接查表就行了。当然可以存到数组中排序,搜后三组时候二分,但是有可能会T(常数大时)。

2048

【题目描述】

小林和亮亮最近正在重温 2048 这款游戏。 由于他们的游戏水平高超, 觉得没有什么挑战性, 于是决定自己设计一款类似的游戏。

他们设计的游戏中, 数字排成了一个线性的序列, 每次玩家可以将序列中任意两个相同的数 a 合并, 成为一个新的数 2*a, 当合并出 2048 时游戏即获得胜利。 设计完后, 他们发现这个游戏比原来的版本更加简单了, 于是他们就开始计算, 对于一个给定的长度为 n 的序列, 它共有多少子序列可以合并出 2048。 请给出这个数模 998244353 后的值。

【输入格式】

第一行有一个整数 n。

第二行 n 个整数 Ai, 表示数列中的数。

【输出格式】

一个整数, 即为所求的答案。

【样例输入】

2
2048 2048

【样例输出】

3

【数据规模】

对于 40%的数据, n <= 20;

对于 70%的数据, n <= 500;

对于 100%的数据, 1 <= n <= 100000, 1 <= Ai <= 2048。

时间限制3秒

【题解】

玩过2048的都知道,要想合成2048,必须用2的幂次合成,并且所有合成的原料的和就是2048。所以我们可以dp,设f[i][j]代表选前i个数,组成j能有多少种方案。方程不难写,f[i][j]=f[i-1][j]+f[i-1][j-a[i]],但是这里建议刷表(推表)。注意到所有数的和可能很大,当数的和大于等于2048时,后边不管怎么加数都没用了,所以可以直接统计到答案里,注意乘上后面数的个数。由于本题时限3秒,这么能过。注意开滚动数组。

还有一种做法就是组合数,由于序列是无序的,我们可以统计每一种2的幂的数量,设f[i][j]为前i种2的幂所有的数组成j的方案,这个的转移就是一个组合数了,并且刷表(推表)要比较好转移。但是由于有组合数,还要打阶乘逆元快速幂。。。

注意到有的数不是2的次幂,他选不选不影响答案,所以答案乘以2的这种数字个数次幂。

posted @ 2018-10-14 21:19  ghj1222  阅读(779)  评论(0编辑  收藏  举报