【BZOJ4866】[YNOI2017] 由乃的商场之旅(莫队)
大致题意: 给你一个字符串,每次给你一段区间,问这段区间内有多少个字符串在重新排列后可以变成一个回文串。
关于莫队
详见这篇博客:莫队算法学习笔记(一)——普通莫队。
关于回文
要使一个字符串在重新排列后可以变成一个回文串,其实只有两种情况:
- 所有字符都出现了偶数次。
- 只有一个字符出现了奇数次,其余字符都出现了偶数次。
关于状压
我们可以用一个\(26\)位的二进制数\(sum_i\)表示\(1\sim i\)范围内每一个字符出现的次数是奇数还是偶数,并用\(cnt_i\)存储状态\(i\)出现的次数。
则不难发现,设当前新加入/删除了一个数\(x\),则改变的贡献值就相当于:\(cnt_x+\sum_{i=0}^{25}cnt_{x\text{^}(1<<i)}\),这应该还是比较好理解的,就相当于枚举哪一个数出现了奇数次。
顺便提一下,为了卡常,这个式子可以循环展开。
关于内存
不难发现,如果开一个大小为\(2^{26}\)的\(int\)数组,会\(MLE\)。
如果开成\(short\),\(cnt_i\)最大为\(60000\),\(short\)显然存不下。
于是我们就要开\(unsigned\ short\),这样就既不会\(MLE\),也不会\(WA\)了。
关于常数
此题似乎略卡常数。
本来即使用了上面提到过的循环展开还是一直\(TLE\),后来发现忘记加莫队一个比较实用的小\(trick\),即在排序时分奇数块与偶数块讨论,一加压时限\(19052ms\)过了。
\(hl666\)神犇告诉我,这题块的大小要开\(2\sqrt N\),一用,果然快了很多,变成了\(16740ms\)。
代码
#include<bits/stdc++.h>
#define N 60000
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
int n,query_tot,a[N+5],Shl[30];
class Class_FIO
{
private:
#define Fsize 100000
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
#define pc(ch) (void)(FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch))
int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
public:
Class_FIO() {A=B=Fin;}
inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
inline void reads(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc()));}
inline void writeln(int x) {if(!x) return pc('0'),pc('\n');while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);pc('\n');}
inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;}
}F;
class Class_CaptainMotao//莫队
{
private:
#define POW 67108864
#define S(p) cnt[x^Shl[p]]
#define Add(val) res+=cnt[x=a[val]]++,res+=S(0)+S(1)+S(2)+S(3)+S(4)+S(5)+S(6)+S(7)+S(8)+S(9)+S(10)+S(11)+S(12)+S(13)+S(14)+S(15)+S(16)+S(17)+S(18)+S(19)+S(20)+S(21)+S(22)+S(23)+S(24)+S(25)//加一个新的元素
#define Del(val) res-=--cnt[x=a[val]],res-=S(0)+S(1)+S(2)+S(3)+S(4)+S(5)+S(6)+S(7)+S(8)+S(9)+S(10)+S(11)+S(12)+S(13)+S(14)+S(15)+S(16)+S(17)+S(18)+S(19)+S(20)+S(21)+S(22)+S(23)+S(24)+S(25)//删除一个原有的元素
int res,block_size,ans[N+5];unsigned short cnt[POW];
public:
struct Query
{
int l,r,pos,bl;
inline friend bool operator < (Query x,Query y) {return x.bl^y.bl?x.bl<y.bl:(x.bl&1?x.r<y.r:x.r>y.r);}//注意加上这个十分实用的小trick
}q[N+5];
inline void Solve()
{
register int i,j,x,L=1,R=0;
for(block_size=min(n,2*sqrt(n)),i=1;i<=query_tot;++i) F.read(q[i].l),F.read(q[i].r),--q[i].l,q[q[i].pos=i].bl=(q[i].l-1)/block_size+1;//读入
for(sort(q+1,q+query_tot+1),i=1;i<=query_tot;++i)
{
while(R<q[i].r) Add(++R);while(L>q[i].l) Add(--L);while(R>q[i].r) Del(R--);while(L<q[i].l) Del(L++);
ans[q[i].pos]=res;//记录答案
}
for(i=1;i<=query_tot;++i) F.writeln(ans[i]);//输出答案
}
}C;
int main()
{
register int i;register string st;
for(i=Shl[0]=1;i<26;++i) Shl[i]=Shl[i-1]<<1;
for(F.read(n),F.read(query_tot),F.reads(st),i=1;i<=n;++i) a[i]=a[i-1]^Shl[st[i-1]-97];//a[i]存储前缀异或和
return C.Solve(),F.clear(),0;
}
【BZOJ4866】[YNOI2017] 由乃的商场之旅(莫队)的更多相关文章
- [bzoj4866] [Ynoi2017]由乃的商场之旅
来自FallDream的博客,未经允许,请勿转载,谢谢, 由乃有一天去参加一个商场举办的游戏.商场派了一些球王排成一行.每个人面前有几堆球.说来也巧,由乃和你一样,觉得这游戏很无聊,于是决定换一个商场 ...
- BZOJ4866 Ynoi2017由乃的商场之旅(莫队)
显然能重排为回文串相当于出现次数为奇数的字母不超过一个.考虑莫队,问题在于如何统计添加/删除一位的贡献.将各字母出现次数奇偶性看做二进制数,做一个前缀和一个后缀和.在右端添加一位时,更新区间的前缀.后 ...
- 【莫队】bzoj4866: [Ynoi2017]由乃的商场之旅
莫队的一些套路 Description 由乃有一天去参加一个商场举办的游戏.商场派了一些球王排成一行.每个人面前有几堆球.说来也巧,由乃和你 一样,觉得这游戏很无聊,于是决定换一个商场.另一个商场是D ...
- 【BZOJ4810】[Ynoi2017]由乃的玉米田 bitset+莫队
[BZOJ4810][Ynoi2017]由乃的玉米田 Description 由乃在自己的农田边散步,她突然发现田里的一排玉米非常的不美.这排玉米一共有N株,它们的高度参差不齐.由乃认为玉米田不美,所 ...
- bzoj 4866: [Ynoi2017]由乃的商场之旅
设第i个字母的权值为1<<i,则一个可重集合可以重排为回文串,当且仅当这个集合的异或和x满足x==x&-x,用莫队维护区间内有多少对异或前缀和,异或后满足x==x&-x,这 ...
- BZOJ4810 Ynoi2017由乃的玉米田(莫队+bitset)
多组询问不强制在线,那么考虑莫队.bitset维护当前区间出现了哪些数,数组记录每个数的出现次数以维护bitset.对于乘法,显然应有一个根号范围内的因子,暴力枚举即可.对于减法,a[i]-a[j]= ...
- BZOJ 4810 [Ynoi2017]由乃的玉米田(莫队+bitset)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4810 [题目大意] 给出一个数列,有三种区间查询, 分别查询区间是否存在两个数乘积为x ...
- 【BZOJ4810】[YNOI2017] 由乃的玉米田(莫队+bitset)
点此看题面 大致题意: 给你一段序列,每次询问一段区间内是否存在两个数的差或和或积为\(x\). 莫队算法 看到区间询问+可以离线,首先想到了莫队啊. 但是,在较短的时间内更新信息依然比较难以实现. ...
- BZOJ 4810 [Ynoi2017]由乃的玉米田 ——Bitset 莫队算法
加法和减法的操作都能想到Bitset. 然后发现乘法比较难办,反正复杂度已经是$O(n\log{n})$了 枚举因数也不能更差了,直接枚举就好了. #include <map> #incl ...
随机推荐
- PostFX v2后期处理特效包:升级更惊艳的视觉效果
https://mp.weixin.qq.com/s/BMkLLuagbhRSWspzeGhK7g Post-Processing Stack后期处理特效包能够轻松创建和调整高质量视觉效果,实现更为惊 ...
- validate验证注册表单
点击预览; <%@ page language="java" contentType="text/html; charset=UTF-8" pageEnc ...
- 遍历json字符串 并 写入对应的文本框
1.js代码: function getFlws(){ var url = urlpath + "bhjk/getJson2.sd?"; $.post(url,function(d ...
- thinkphp5使用querylist采集图片示例
首先composer引入querylist composer require jaeger/querylist 注意需要php7.0以上版本 <?php namespace app\index\ ...
- CDN-内容发布网络
整理<CDN技术详解>一书中重要的内容. 互联网与万维网 广义的互联网,由两层组成:一层是以TCP/IP为代表的网络层:另一层是以万维网WWW为代表的应用层.辨识互联网和万维网的区别,是认 ...
- Ubuntu16.04双网卡绑定
服务器经常有多个网卡,为了保证网络冗余性,一个网卡出现故障时,不导致网络服务中断,可以懂多网卡网卡绑定来解决此问题. 环境: 系统:Ubuntu16.04 网卡:em1 em2 ip:192.168. ...
- lifecycle-mapping-metadata.xml
<?xml version="1.0" encoding="UTF-8"?> <lifecycleMappingMetadata> &l ...
- 练习二十:python计算皮球下落速度练习题
问题简述:假设一个皮球从100米高度自由落下.条件,每次落地后反跳回原高度的一般,在落下 要求:算出皮球,在第十次落地时,共经过多少米?第十次反弹多高? 方法一: h,sum1 = 100,100 # ...
- 【ACM】拦截导弹 - 0-1背包问题
拦截导弹 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到 ...
- LeetCode 260 Single Number III 数组中除了两个数外,其他的数都出现了两次,找出这两个只出现一次的数
Given an array of numbers nums, in which exactly two elements appear only once and all the other ele ...