棠梨煎雪
题目背景
岁岁花藻檐下共将棠梨煎雪
自总角至你我某日辗转天边
天淡天青 宿雨沾襟
一年一会信笺却只见寥寥数言
——银临《棠梨煎雪》
题目描述
扶苏正在听《棠梨煎雪》的时候,@spitfirekindergarten 发来一道IOI2018集训队作业题:我切了这集训队题,辣鸡扶苏快过来做题。扶苏定睛一看,这不s*题嘛,写了一发交上去才发现自己看错题目了。但是写完的代码不能浪费,于是就有了这道题。
歌词中的主人公与她的朋友一年会有一次互相写信给对方,一共通信了 mm 年。为了简化问题,我们认为她们每封信的内容都是一条二进制码,并且所有二进制码的长度都是 nn。即每封信的内容都是一个长度为 nn的字符串,这个字符串只含字符 0
或 1
。
这天她拿出了朋友写给她的所有信件,其中第 ii 年的写的信件编号为 ii。由于信件保存时间过久,上面有一些字符已经模糊不清,我们将这样的位置记为 ?
,?
字符可以被解释为 0
或 1
。由于她的朋友也是人,符合人类的本质,所以朋友在一段连续的时间中书写的内容可能是相同的。现在她想问问你,对于一段连续的年份区间 [l,~r][l, r] 中的所有信件,假如朋友在这段时间展示了人类的本质,所写的是同一句话,那么这一句话一共有多少种可能的组成。也即一共有多少字符串 SS,满足在这个区间内的所有信件的内容都可能是 SS。
一个长度为 nn 的只含 0,1,?
的字符串 AA 可能是一个字符串 BB 当且仅当 BB 满足如下条件:
BB 的长度也是 nn
BB 中只含字符
0,1
AA 中所有为
0
的位置在 BB 中也是0
AA 中所有为
1
的位置在 BB 中也是1
AA 中为
?
的位置在 BB 中可以为0
也可以是1
同时她可能会突然发现看错了某年的信的内容,于是她可能会把某一年的信的内容修改为一个别的只含 0
,1
,?
的长度为 nn 的字符串。
输入格式
每个输入文件中都有且仅有一组测试数据。
输入数据第一行为三个正整数 n,~m,~qn, m, q,代表字符串长度,字符串个数和操作次数。
下面 mm 行,每行是一个长度为 nn 的字符串,第 ii 个字符串代表第 ii 年信的内容。
下面 qq 行,每行的第一个数字是操作编号 optopt。
如果 opt=0opt=0,那么后面接两个整数 [l,~r][l, r],代表一次查询操作
如果 opt=1opt=1,那么后面接一个整数 pospos,在一个空格后会有一个长度为 nn 的字符串,代表将第 pospos 个字符串修改为新的字符串。
输出格式
为了避免输出过大,请你输出一行一个数代表所有查询的答案异或和对 00 取异或的结果
输入输出样例
3 3 5 010 0?0 1?0 0 1 2 0 2 3 1 3 0?? 0 2 3 0 1 3
2
说明/提示
样例解释
对于第一次询问,只有串 010
符合要求
对于第二次询问,由于第二个串的第一位为 1
,第三个串的第一位为 0
,故没有串符合要求
修改后将第三个串修改为 0??
对于第四次询问,有两个串符合要求,分别为 000
和 010
对于第五次询问,只有 010
符合要求。
故答案为1 0 2 1,他们的异或和再异或 00 的值为2
数据范围
本题采用多测试点捆绑测试
各个子任务的数据范围见下表
部分子任务可能会出现卡常的情况,请注意常数因子对程序效率造成的影响
请注意输入的问号为嘤文问号,即其 ASCII
码值为 6363。
我们保证数据是在Linux下生成的,即换行符不含\r
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 1e5 + 8; const int N = 36; int n, m, q; char str[maxn][N]; int f[maxn << 2][N]; struct data { int s, t; }; data operator|(data p, data q) { return (data) {p.s | q.s, p.t | q.t}; } inline void pushup(int rt) { f[rt][0] = f[rt << 1][0] | f[rt << 1 | 1][0]; f[rt][1] = f[rt << 1][1] | f[rt << 1 | 1][1]; } inline void build(int l, int r, int rt) { if (l == r) { int len = strlen(str[l] + 1); for (register int i = 1; i <= n; ++i) { if (str[l][i] == '?')continue; f[rt][str[l][i] - '0'] |= (1 << (i - 1)); //printf("debug f[%d][str[l][i]] = %d\n", rt, f[rt][str[l][i] - '0']); } return; } int mid = l + r >> 1; build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1); pushup(rt); } inline void update(int l, int r, int rt, int pos, char *s) { if (l == r) { f[rt][0] = f[rt][1] = 0; for (register int i = 0; i < n; ++i) { if (s[i] == '?')continue; f[rt][s[i] - '0'] |= (1 << i); } return; } int mid = l + r >> 1; if (pos <= mid)update(l, mid, rt << 1, pos, s); else update(mid + 1, r, rt << 1 | 1, pos, s); pushup(rt); } inline data query(int l, int r, int ql, int qr, int rt) { if (ql <= l && qr >= r) { return (data) {f[rt][0], f[rt][1]}; } int mid = l + r >> 1; if (qr <= mid) { return query(l, mid, ql, qr, rt << 1); } else if (ql > mid) { return query(mid + 1, r, ql, qr, rt << 1 | 1); } else { return query(l, mid, ql, qr, rt << 1) | query(mid + 1, r, ql, qr, rt << 1 | 1); } } char tp[36]; int res; int main() { //freopen("1.txt", "r", stdin); scanf("%d%d%d", &n, &m, &q); for (register int i = 1; i <= m; ++i) { scanf("%s", str[i] + 1); } build(1, m, 1); int op; while (q--) { scanf("%d", &op); if (op == 0) { int l, r; scanf("%d%d", &l, &r); data cur = query(1, m, l, r, 1); int ans = 1; //printf("debug cur.s = %d cur.t = %d\n", cur.s, cur.t); for (register int i = 1; i <= n; ++i) { if ((cur.s & 1) && (cur.t & 1)) { ans = 0; break; } if (!(cur.s & 1) && !(cur.t & 1)) { ans *= 2; } cur.s >>= 1; cur.t >>= 1; } //printf("debug ans = %d\n", ans); res = res ^ ans; //printf("debug res = %d\n", res); } else { int id; scanf("%d%s", &id, tp + 1); update(1, m, 1, id, tp + 1); } } printf("%d\n", res); return 0; }