BZOJ4943 & 洛谷3823 & UOJ315:[NOI2017]蚯蚓排队——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4943

http://uoj.ac/problem/315

https://www.luogu.org/problemnew/show/P3823#sub

题面太长自己看吧orz。

参考:洛谷题解。

用链表暴力维护每个蚯蚓,每次合并和分离只对k*k的元素有影响,哈希一下存起来query时候比较就好了。

没了。

(具体复杂度我不会证明,以及bzoj卡空间,正常的哈希表空间总觉得不能开如代码所示的这么小。)

(自然溢出hash真的块)

#include<cmath>
#include<stack>
#include<vector>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=2e5+5;
const int K=50;
const int mod=998244353;
const int p=19260817;
const int B=13;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==‘-‘;ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int nxt,cnt;
    ll w;
}e[21000000];
char s[10000005];
int n,m,cnt,head[p+5],t[10],a[N];
int nxt[N],pre[N];
ull f[K*2+5],base[K+5];
inline void add(ull w,int on){
    int u=w%p;
    for(int i=head[u];i;i=e[i].nxt){
    if(e[i].w==w){
        e[i].cnt+=on;return;
    }
    }
    e[++cnt].cnt=1;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
inline int ask(ull w){
    int u=w%p;
    for(int i=head[u];i;i=e[i].nxt){
    if(e[i].w==w)return e[i].cnt;
    }
    return 0;
}
void merge(int x,int y){
    int l=K+1,r=K;
    memset(f,0,sizeof(f));
    for(int i=x;i&&l>1;i=pre[i])f[--l]=a[i];
    for(int j=y;j&&r<2*K;j=nxt[j])f[++r]=a[j];
    for(int i=l;i<=r;i++)f[i]+=f[i-1]*B;
    for(int i=l;i<=K;i++){
    for(int j=K+1;j<=min(r,i+K-1);j++){
        add(f[j]-f[i-1]*base[j-i+1],1);
    }
    }
    nxt[x]=y;pre[y]=x;
}
void split(int x,int y){
    int l=K+1,r=K;
    memset(f,0,sizeof(f));
    for(int i=x;i&&l>1;i=pre[i])f[--l]=a[i];
    for(int j=y;j&&r<2*K;j=nxt[j])f[++r]=a[j];
    for(int i=l;i<=r;i++)f[i]+=f[i-1]*B;
    for(int i=l;i<=K;i++){
    for(int j=K+1;j<=min(r,i+K-1);j++){
        add(f[j]-f[i-1]*base[j-i+1],-1);
    }
    }
    nxt[x]=0;pre[y]=0;
}
int query(int k){
    ll ans=1;ull val=0;int len=strlen(s+1);
    if(k==1)
    for(int i=1;i<=len;i++)
        ans=ans*t[s[i]-‘0‘]%mod;
    else{
    for(int i=1;i<=len;i++){
        val=val*B+s[i]-‘0‘;
        if(i>k)val-=base[k]*(s[i-k]-‘0‘);
        if(i>=k)ans=ans*ask(val)%mod;
    }
    }
    return ans;
}
int main(){
    n=read(),m=read();
    base[0]=1;
    for(int i=1;i<=K;i++)base[i]=base[i-1]*B;
    for(int i=1;i<=n;i++){
    a[i]=read();t[a[i]]++;
    }
    for(int i=1;i<=m;i++){
    int op=read();
    if(op==1){
        int x=read(),y=read();
        merge(x,y);
    }
    if(op==2){
        int x=read();
        split(x,nxt[x]);
    }
    if(op==3){
        scanf("%s",s+1);
        int k=read();
        printf("%d\n",query(k));
    }
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

原文地址:https://www.cnblogs.com/luyouqi233/p/9050287.html

时间: 2024-10-09 15:05:28

BZOJ4943 & 洛谷3823 & UOJ315:[NOI2017]蚯蚓排队——题解的相关文章

洛谷3768:简单的数学题——题解

https://www.luogu.org/problemnew/show/P3768 题面来自洛谷,因为没用markdown所以直接截的图. 剩余的图是我用markdown写完然后截的图. 参考洛谷第一篇题解. 这个式子直观感受就需要莫比乌斯反演,大致的过程参考:BZOJ2693:jzptab 那么跳过暴力推式子,我们能够得到: (如果你疑问为什么是miu(k/d)而不是miu(d),其实二者皆可,但是为什么这么干请往下看) 显然可以分块O(sqrt(n))做,那么后面的那一串东西怎么做呢?

洛谷3919:可持久化数组——题解

https://www.luogu.org/problemnew/show/P3919 如题,你需要维护这样的一个长度为 N 的数组,支持如下几种操作 在某个历史版本上修改某一个位置上的值 访问某个历史版本上的某一位置的值 此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本.版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组) 这题题意看错了就很伤……操作2新建的版本是它所询问的历史版本emmm…… 以及各种小错误,int没retur

bzoj4943 [Noi2017]蚯蚓排队

题面暂缺.. 正解:字符串$hash$. 我在考场上写了个$map$的$hash$被卡成$40$分,然后改成挂链版本的就$AC$了..$mdzz$,以后$hash$再也不写$map$了.. 我们考虑使用链表来表示字符间的关系,合并和分裂都用链表来表示,这样我们可以快速找到两个字符的前$k$个和后$k$个字符. 注意到每次只会增加或减少$k^{2}$个字符串,那么我们直接把这些字符串$hash$起来即可,查询统计也很简单. 这道题好像是被骂得最惨的一道题?? 1 //It is made by w

洛谷 P1005 矩阵取数游戏 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1005 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元

洛谷 P1507 NASA的食物计划 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1507 题目背景 NASA(美国航空航天局)因为航天飞机的隔热瓦等其他安 全技术问题一直大伤脑筋,因此在各方压力下终止了航天 飞机的历史,但是此类事情会不会在以后发生,谁也无法 保证,在遇到这类航天问题时,解决方法也许只能让航天 员出仓维修,但是多次的维修会消耗航天员大量的能量, 因此NASA便想设计一种食品方案,让体积和承重有限的 条件

BZOJ3343 &amp; 洛谷2801:教主的魔法——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=3343 https://www.luogu.org/problemnew/show/2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整

洛谷P1047校门外的树题解

摘要: 此题是一个模拟题,但需要注意的一点就是它的树是从数轴的0开始,所以我们也要从0开始,这样才能实现代码. 代码: #include<iostream> using namespace std; int s[100000]; int main() { int l,m,x,y,d=0; cin>>l>>m; for(int i=0; i<=l; i++) s[i]=1; for(int i=0; i<m; i++) { cin>>x>&g

【p1897】洛谷P1897电梯里的爱情题解

这个题是一个搜索题,可以先算出最高楼层,并算出不重复的楼层的个数,要注意的一点就是一定不要把0楼算在内. 代码 #include<iostream> #include<cstring> #include<bits/stdc++.h> using namespace std; int n,a[1000010],b[1000010],ans=0,maxn=-1,sum=0; int main() { cin>>n; for(int i=0; i<n; i+

洛谷 P1101 【单词方阵】题解

来先写一下思路: 1.一一枚举开始的位置 2.朝8个方向搜索(其实不如说是递归) 3.在搜索到后标记搜索到了 4.通过标记在搜索完成后再标记哪些地方是"yizhong" 5.输出 严格来说,此题不算是深搜,到不如说是递归,因为只需要往前探路,不需要回溯,下面是代码: #include<iostream>#include<cstdio>using namespace std;int pd,wx[9] = {0,-1,-1,0,1,1,1,0,-1},wy[9] =