B 洛谷 P3604 美好的每一天 [莫队算法]

题目背景

时间限制3s,空间限制162MB

素晴らしき日々

我们的情人,不过是随便借个名字,用幻想吹出来的肥皂泡,把信拿去吧,你可以使假戏成真。我本来是无病呻吟,漫无目的的吐露爱情---现在这些漂泊不定的鸟儿有地方栖息了,你可以从信里看出来。拿去吧---由于不是出自真心,话就说得格外动听,拿去吧,就这么办吧...

由于世界会在7月20日完结,作为救世主,间宫卓司要在19日让所有人回归天空

现在已经是19日傍晚,大家集合在C栋的天台上,一共n个人

在他们面前,便是终之空,那终结的天空

题目描述

回归天空是一件庄重的事情,所以卓司决定让大家分批次进行,给每个人给了一个小写字母‘a‘->‘z‘作为编号

一个区间的人如果满足他们的编号重排之后可以成为一个回文串,则他们可以一起回归天空,即这个区间可以回归天空

由于卓司是一个喜欢妄想的人,他妄想了m个区间,每次他想知道每个区间中有多少个子区间可以回归天空

因为世界末日要来了,所以卓司的信徒很多

输入输出格式

输入格式:

第一行两个数n,m

之后一行一个长为n的字符串,代表每个人的编号

之后m行每行两个数l,r代表每次卓司妄想的区间

输出格式:

m行,每行一个数表示答案

输入输出样例

输入样例#1:

6 6
zzqzzq
1 6
2 4
3 4
2 3
4 5
1 1

输出样例#1:

16
4
2
2
3
1

说明

对于10%的数据,n,m<=100

对于30%的数据,n,m<=2000

对于100%的数据,n,m<=60000

字符集大小有梯度

在大家回归天空之后,彩名露出了阴冷的笑容



先奉上O(n2) 30分骗分

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=2005;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();}
    return x*f;
}
int n,Q,l,r;
char c[N];
int a[N][N],s[N][N],cnt[300],now;
void ini(){
    for(int i=1;i<=n;i++){
        memset(cnt,0,sizeof(cnt));now=0;
        for(int j=i;j<=n;j++){
            if(cnt[c[j]]%2==0) now++;
            else now--;
            cnt[c[j]]++;
            if((j-i+1)%2==0&&now==0) a[i][j]=1;
            if((j-i+1)%2==1&&now==1) a[i][j]=1;
            s[i][j]=s[i][j-1]+a[i][j];
            //printf("hi %d %d %d  %d\n",i,j,a[i][j],s[i][j]);
        }
    }
}
void solve(int l,int r){
    int ans=0;
    for(int i=l;i<=r;i++) ans+=s[i][r]-s[i][i-1];
    printf("%d\n",ans);
}
int main(int argc, const char * argv[]) {
    n=read();Q=read();
    scanf("%s",c+1);
    ini();
    while(Q--){
        l=read();r=read();
        solve(l,r);
    }
    return 0;
}

标解:

一个区间可以重排成为回文串,即区间中最多有一个字母出现奇数次,其他的都出现偶数次

发现这个和  类似





这样如果一个区间的  和为  或者  ,则这个区间可以重排成为回文串,即回归天空

把每个位置的值变为前缀  和,那么区间  可以回归天空当且仅当  为  或者 

 即  的异或和

这样用莫队算法,可以做到  的复杂度

怎么用莫队呢?去请教了__stdcall

考虑[l,r]—>[l,r+1],就是要找出这个区间里有几个前缀xor满足 a[r+1]^它 =0或(1<<x)

那么用一个桶c存起来 更新答案加上c[a[r+1]^(1<<x)]和c[a[r+1]]就行了

有个细节,[l,r]对应的桶中应该是[l-1,r]的a

然后内存原因c用short

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=6e4+5,M=(1<<26)+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();}
    return x*f;
}
int n,Q,a[N],bl,pos[N];
char s[N];
struct ques{
    int l,r,id;
    bool operator <(const ques &a)const{
        return pos[l]==pos[a.l]?r<a.r:pos[l]<pos[a.l];
    }
}q[N];
unsigned short c[M];
int ans,anss[N];
inline void add(int x){//printf("add %d %d\n",x,a[x]);
    ans+=c[a[x]];
    for(int i=0;i<26;i++) ans+=c[a[x]^(1<<i)];
    c[a[x]]++;
}
inline void del(int x){
    c[a[x]]--;
    ans-=c[a[x]];
    for(int i=0;i<26;i++) ans-=c[a[x]^(1<<i)];
}
void solve(){
    sort(q+1,q+1+Q);
    c[0]++;
    int l=1,r=0;
    for(int i=1;i<=Q;i++){//printf("Q %d %d %d\n",q[i].l,q[i].r,q[i].id);
        while(r<q[i].r) r++,add(r);//printf("hi %d %d %d\n",l,r,ans);
        while(r>q[i].r) del(r),r--;//printf("hi %d %d %d\n",l,r,ans);
        while(l<q[i].l) del(l-1),l++;//printf("hi %d %d %d\n",l,r,ans);
        while(l>q[i].l) l--,add(l-1);//printf("hi %d %d %d\n",l,r,ans);
        anss[q[i].id]=ans;
    }
    for(int i=1;i<=Q;i++) printf("%d\n",anss[i]);
}
int main(int argc, const char * argv[]) {
    n=read();Q=read();
    scanf("%s",s+1);
    bl=sqrt(n);
    for(int i=1;i<=n;i++) a[i]=(1<<(s[i]-‘a‘))^a[i-1],pos[i]=(i-1)/bl+1;
    for(int i=1;i<=Q;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
    solve();
    return 0;
}

怎么卡常也还是70分

//
//  main.cpp
//  BB
//
//  Created by Candy on 2017/2/2.
//  Copyright © 2017年 Candy. All rights reserved.
//
#pragma GCC optimize("O2")

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=6e4+5,M=(1<<26)+5;
inline int read(){
    char c=getchar();register int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();}
    return x*f;
}
int n,Q,a[N],bl,pos[N],bit[27];
char s[N];
struct ques{
    int l,r,id;
    bool operator <(const ques &a)const{
        return pos[l]==pos[a.l]?r<a.r:pos[l]<pos[a.l];
    }
}q[N];
unsigned short c[M];
int ans,anss[N];
inline void add(int x){//printf("add %d %d\n",x,a[x]);
    ans+=c[a[x]]++;
    for(register int i=0;i<26;i++) ans+=c[a[x]^bit[i]];
}
inline void del(int x){
    ans-=--c[a[x]];
    for(register int i=0;i<26;i++) ans-=c[a[x]^bit[i]];
}
inline void solve(){
    for(int i=0;i<26;i++) bit[i]=1<<i;
    sort(q+1,q+1+Q);
    c[0]++;
    int l=1,r=0;
    for(int i=1;i<=Q;i++){//printf("Q %d %d %d\n",q[i].l,q[i].r,q[i].id);
        while(r<q[i].r) add(++r);//printf("hi %d %d %d\n",l,r,ans);
        while(r>q[i].r) del(r--);//printf("hi %d %d %d\n",l,r,ans);
        while(l<q[i].l) del(l-1),l++;//printf("hi %d %d %d\n",l,r,ans);
        while(l>q[i].l) add(--l-1);//printf("hi %d %d %d\n",l,r,ans);
        anss[q[i].id]=ans;
    }
    for(int i=1;i<=Q;i++) printf("%d\n",anss[i]);
}
int main(int argc, const char * argv[]) {
    n=read();Q=read();
    scanf("%s",s+1);
    bl=sqrt(n);
    for(int i=1;i<=n;i++) a[i]=(1<<(s[i]-‘a‘))^a[i-1],pos[i]=(i-1)/bl+1;
    for(int i=1;i<=Q;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
    solve();
    return 0;
}

卡常后很丑

时间: 2024-11-04 16:29:52

B 洛谷 P3604 美好的每一天 [莫队算法]的相关文章

洛谷 P3674 小清新人渣的本愿 [莫队 bitset]

传送门 题意: 给你一个序列a,长度为n,有Q次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3 题面太强啦!!! 感觉就是莫队,想了一下分块不好搞更坚定了莫队的信念 $a-b=x$,$a=x+b$,放在权值数组上就是b右移x位,$bitset$大法好 加法同理 乘法,总共就$\sqrt{N}$个约数.... #include <iostream> #incl

洛谷 P2056 采花 - 莫队算法

萧芸斓是 Z国的公主,平时的一大爱好是采花. 今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花.花园足够大,容纳了 n 朵花,花有 c 种颜色(用整数 1-c 表示) ,且花是排成一排的,以便于公主采花. 公主每次采花后会统计采到的花的颜色数, 颜色数越多她会越高兴! 同时, 她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵.为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花. 由于时间关系,公主只能走过花园连续的一段进行采

洛谷 P3227 BZOJ 3144 [HNOI2013]切糕

题目描述 经过千辛万苦小 A 得到了一块切糕,切糕的形状是长方体,小 A 打算拦腰将切糕切成两半分给小 B.出于美观考虑,小 A 希望切面能尽量光滑且和谐.于是她找到你,希望你能帮她找出最好的切割方案. 出于简便考虑,我们将切糕视作一个长 P.宽 Q.高 R 的长方体点阵.我们将位于第 z层中第 x 行.第 y 列上(1≤x≤P, 1≤y≤Q, 1≤z≤R)的点称为(x,y,z),它有一个非负的不和谐值 v(x,y,z).一个合法的切面满足以下两个条件: 与每个纵轴(一共有 P*Q 个纵轴)有且

Cogs 2856. [洛谷U14475]部落冲突

2856. [洛谷U14475]部落冲突 ★★★   输入文件:lct.in   输出文件:lct.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多可歌可泣的动人故事. 其中,在大大小小的部落之间,会有一些道路相连,这些道路是Travian世界里的重要枢纽,简单起见,你可以把这

洛谷 模拟城市2.0

一次洛谷月赛的T1,当时因为是信心赛,认为第一题应该不会太难,结果想了很久,直接额放弃正解选择暴力...简直就是巨坑的五维DP...mmd 题目背景 博弈正在机房颓一个叫做<模拟城市2.0>的游戏. 2048年,经过不懈努力,博弈终于被组织委以重任,成为D市市委书记! 他勤学好问,励精图治,很快把D市建设成富强民主文明和谐的美好城市.为了进一步深化发展,他决定在海边建立一个经济开发区. 题目描述 已知开发区的建筑地块是一个n×n的矩形,而开发区可以建造三种建筑: 商业楼,住宅楼,教学楼.这任何

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

洛谷1231 教辅的组成

洛谷1231 教辅的组成 https://www.luogu.org/problem/show?pid=1231 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题.然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册.已知一个完整的书册均应该包含且仅包含一本书.一本练习册和一份答案,然而现在全都乱做了一团.许多书上面的字迹都已经模糊了,然而HansBug还是可

洛谷教主花园dp

洛谷-教主的花园-动态规划 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高. 输入输出格式 输入格式: 输入文件garden.in的第1行为一个正整数n,表示需要种的

洛谷 P2801 教主的魔法 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不