都得死(die)

  • 每个测试点时限:\(1.5\) s
  • 内存限制:\(256\) MB
  • 编译选项:-lm -std=c++14 -O2

【题目背景】

2021.9.3 晚,大家在讨论出题的名字
ycx:就叫第一题、第二题 \(\cdots\cdots\)
cyh:毛
mtr:(大笑)就用 cyh 的口头禅吧
cyh:都得死

于是有了这道题

【题目描述】

一个字符串 \(s\),您需要完成以下操作:

  • 1 l c 在第 \(l\) 个字符后插入字符 \(c\)
  • 2 l 删除第 \(l\) 个字符
  • 3 l r 翻转 \([l,r]\) 内的字符,即将第 \(l\) 个到第 \(r\) 个字符逆序
  • 4 l r 询问将 \([l,r]\) 内任意个字符重新排列后能形成的字典序最小的最长回文串长度和回文中心

回文中心定义为一个回文串最中间的一个(串长为奇数)或两个(串长为偶数)字符

【输入格式】

第一行两个整数:\(n,m\),表示 \(s\) 初始长度和操作数
第二行 \(n\) 个字符,表示 \(s\)
接下来 \(m\) 行,每行表示一次操作,格式见【题目描述】

【输出格式】

对于操作 \(4\) 输出一行空格隔开的一个整数和一个或两个字符,表示最长回文串长度和回文中心

【样例】

  • 样例 \(1\) 输入
4 5
aabb
4 3 4
3 2 4
2 2
1 1 a
4 1 3
  • 样例 \(1\) 输出
2 bb
3 b
  • 样例 \(1\) 解释
操作 \(s\) 答案串
\ aabb \
4 3 4 aabb bb
3 2 4 abba \
2 2 aba \
1 1 a aaba \
4 1 3 aaba aba
  • 样例 \(2\) 输入
9 15
bbaaabcab
4 4 5
4 2 7
2 3
4 1 2
1 6 a
2 3
4 3 8
2 4
4 4 4
4 2 4
4 4 5
1 0 c
2 3
4 5 7
1 5 b
  • 样例 \(2\) 输出
2 aa
5 a
2 bb
5 a
1 c
1 a
1 a
3 b

【测试点约束】

本题采用捆绑测试

Subtask \(n,m\le\) 特殊性质 分值
1 \(20\) \ \(10\)
2 \(10^4\) \ \(10\)
3 \(5\times10^5\) A \(10\)
4 \(2\times10^5\) B C \(10\)
5 \(2\times10^5\) C \(20\)
6 \(2\times10^5\) \ \(20\)
7 \(5\times10^5\) \ \(20\)

特殊性质 A:所有 \(s_i,c\) 相同
特殊性质 B:不存在操作 \(1,2\)
特殊性质 C:不存在操作 \(3\)

保证 \(s_i,c\) 为小写英文字母;\(l\le r\);任意时刻 \(|s|>0\)


出题人:401rk8
验题人:kai586213

sol

sub 1

乱搞 / 不知道哪里写挂了。

sub 2

考虑如何排列字符,显然是将相同字符两两配对,如果有一种字符出现奇数次则放在中间,\(O(n)\) 统计区间内每个字符出现次数即可。

时间复杂度 \(O(mn)\)

sub 3

所有字符都相同,则最长回文串长为区间长度,回文中心判一下奇偶性即可,\(O(n+m)\)

sub 4

不带修改,对每种字母出现次数做前缀和,\(O(26n+26m)\)

sub 5

只有插入、删除、区间查询,块状链表即可,时间复杂度 \(O(26n\sqrt n)\)

upd: 离线离散化位置,建树时留下插入的位置,线段树二分修改,区间查询。by ycx

sub 6

文艺平衡树,时间复杂度 \(O(26n\log n)\) / 正解被卡常。

upd: 突然想到块状链表也能做,我当时傻了。

sub 7

考虑去掉常数 \(26\)
显然出现次数为奇数的字符只能留下字典序最小的一个,只需状压每个字符出现次数的奇偶性。
字典序最小时的回文中心再状压一下每种字符是否出现即可。

评价

部分分充足、码量小、思维套路的签到题

数据很水,因此调大了范围,略微卡常

事实上,出题人只写了 sub 2,7,其他都是口胡的

std

最大测试点:1.05s

#include <bits/stdc++.h>
using namespace std;
#define For(i,x,y) for(int i=x;i<=y;++i)
#define rFor(i,x,y) for(int i=x;i>=y;--i)
#define mem(a,x,n) memset(a,x,sizeof(a[0])*(n+1))
#define pb emplace_back
#define MP make_pair
#define fi first
#define se second
typedef long long LL; typedef unsigned long long ULL; typedef long double LD;
typedef pair<int,int> PII; typedef vector<int> VI;
char buf[1<<21],*p1=buf,*p2=buf,pbuf[1<<21],*pp=pbuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#define iocl() fwrite(pbuf,1,pp-pbuf,stdout),pp=pbuf,0
#define putchar(x) pp-pbuf==1<<21&&(iocl()),*pp++=x
template<typename T>void read(T &x){
	x=0;char c=getchar();
	while(!isdigit(c))c=getchar();
	for(;isdigit(c);c=getchar())x=x*10+c-48;
}
template<typename T,typename ...Args>void read(T &x, Args &...args)
	{ read(x),read(args...); }
template<typename T>void write(T x,char y=10) {
	if(!x)putchar(48);
	else{static int s[21];int l=0;
		for(;x;x/=10)s[l++]=x%10;while(l)putchar(s[--l]|48);}
	putchar(y);
}
template<typename T>void ckmax(T &x,T y) { if( y > x ) x = y; }
template<typename T>void ckmin(T &x,T y) { if( y < x ) x = y; }

mt19937 mt(time(0));

const int N = 1.2e6+5;
int n,m;

int readc() { char c=getchar(); while(!islower(c))c=getchar(); return 1<<c-'a'; }

#define ls(u) t[u].ls
#define rs(u) t[u].rs
int rt,ind;
struct Node { int ls,rs,siz,val,_xor,_or; bool rev; unsigned rnd; } t[N];
int newnode(int x) { return t[++ind] = Node{0,0,1,x,x,x,0,mt()}, ind; }
void up(int u) {
	t[u].siz = t[ls(u)].siz + t[rs(u)].siz + 1,
	t[u]._xor = t[ls(u)]._xor ^ t[rs(u)]._xor ^ t[u].val;
	t[u]._or = t[ls(u)]._or | t[rs(u)]._or | t[u].val;
}
void down(int u) { if( t[u].rev ) {
	swap(ls(u),rs(u)), t[u].rev = 0;
	if( ls(u) ) t[ls(u)].rev ^= 1; if( rs(u) ) t[rs(u)].rev ^= 1;
}}
void split(int u,int k,int &l,int &r) {
	if( !u ) return l = r = 0, void();
	down(u);
	if( k <= t[ls(u)].siz ) r = u, split(ls(u),k,l,ls(r)), up(r);
	else l = u, split(rs(u),k-t[ls(u)].siz-1,rs(l),r), up(l);
}
int merge(int l,int r) {
	if( !l || !r ) return l | r;
	if( t[l].rnd < t[r].rnd ) return down(l), rs(l) = merge(rs(l),r), up(l), l;
	else return down(r), ls(r) = merge(l,ls(r)), up(r), r;
}
void insert(int x,int c) {
	int l,r; split(rt,x,l,r);
	rt = merge(merge(l,newnode(c)),r);
}
void erase(int x) {
	int l,r,mid; split(rt,x,l,r), split(l,x-1,l,mid);
	rt = merge(l,r);
}
void rev(int x,int y) {
	int l,mid,r; split(rt,y,l,r), split(l,x-1,l,mid);
	t[mid].rev ^= 1, rt = merge(merge(l,mid),r);
}
#undef ls
#undef rs

signed main() {
    freopen("die.in","r",stdin);
    freopen("die.out","w",stdout);
	read(n,m); For(i,1,n) insert(i-1,readc());
	while( m-- ) {
		int op,x,y; read(op);
		switch(op) {
			case 1: read(x); insert(x,readc()), ++n; break;
			case 2: read(x); erase(x), --n; break;
			case 3: read(x), read(y); rev(x,y); break;
			default: read(x), read(y);
				int l,mid,r; split(rt,y,l,r), split(l,x-1,l,mid);
				int _xor = t[mid]._xor, _or = t[mid]._or, ans;
				rt = merge(merge(l,mid),r);
				write( ans = y-x+1 - max(__builtin_popcount(_xor)-1,0) ,' ');
				if( ans & 1 ) putchar(__builtin_ctz(_xor)+'a');
				else { char c=log2(_or)+'a'; putchar(c), putchar(c); }
				putchar(10);
		}
	}
	return iocl();
}

总结

得分情况:
\(40\) pts: 1
\(0\): 6
远低于预期

部分分设置有点问题(sub 5,6),导致特殊性质只能拿到 \(40\) pts,但为什么只有一个人
从提交的代码上看只有 ycx 一人写了 \(80\) pts 做法