[SD2014集训]查询(分块+数学相关)
来源:互联网 发布:centos7.0安装nginx 编辑:程序博客网 时间:2024/05/29 14:13
题目描述
题解
看模数那么奇怪找一下规律看看有没有奇怪的性质
发现每一个数立方48次后回到原数
线段树不如分块好写
维护每个数立方k次后得到的数,每一个块所有的数分别立方k次后的和
修改时,对于整块记录立方的次数,其余的暴力重构
重构即把块内的点维护的立方旋转t次,然后重新计算和
查询时,整块直接查询,其余暴力
时间复杂度
代码
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define LL long long#define Mod 329701061#define sz 48#define N 100005char opt;int n,m,x,y,block,tot;int t[N],num[N],l[N],r[N];LL a[N],cub[N][sz],Cub[N][sz],s[sz];void init(){ for (int i=1;i<=n;++i) { cub[i][0]=a[i]; for (int j=1;j<sz;++j) cub[i][j]=cub[i][j-1]*cub[i][j-1]%Mod*cub[i][j-1]%Mod; } for (int i=1;i<=tot;++i) for (int j=0;j<sz;++j) for (int k=l[i];k<=r[i];++k) { Cub[i][j]+=cub[k][j]; if (Cub[i][j]>=Mod) Cub[i][j]-=Mod; }}void move(int id,int rad){ if (!rad) return; for (int i=0;i<rad;++i) s[i]=cub[id][i]; for (int i=rad;i<sz;++i) cub[id][i-rad]=cub[id][i]; for (int i=0;i<rad;++i) cub[id][i+sz-rad]=s[i];}void calc(int id){ for (int i=0;i<sz;++i) { Cub[id][i]=0; for (int j=l[id];j<=r[id];++j) { Cub[id][i]+=cub[j][i]; if (Cub[id][i]>=Mod) Cub[id][i]-=Mod; } }}void change(int x,int y){ if (num[x]==num[y]) { for (int i=l[num[x]];i<x;++i) move(i,t[num[x]]); for (int i=y+1;i<=r[num[y]];++i) move(i,t[num[x]]); ++t[num[x]];if (t[num[x]]==sz) t[num[x]]=0; for (int i=x;i<=y;++i) move(i,t[num[x]]); t[num[x]]=0; calc(num[x]); return; } if (x==l[num[x]]) x=num[x]; else { for (int i=l[num[x]];i<x;++i) move(i,t[num[x]]); ++t[num[x]];if (t[num[x]]==sz) t[num[x]]=0; for (int i=x;i<=r[num[x]];++i) move(i,t[num[x]]); t[num[x]]=0; calc(num[x]); x=num[x]+1; } if (y==r[num[y]]) y=num[y]; else { for (int i=y+1;i<=r[num[y]];++i) move(i,t[num[y]]); ++t[num[y]];if (t[num[y]]==sz) t[num[y]]=0; for (int i=l[num[y]];i<=y;++i) move(i,t[num[y]]); t[num[y]]=0; calc(num[y]); y=num[y]-1; } for (int i=x;i<=y;++i) { ++t[i]; if (t[i]==sz) t[i]=0; }}LL query(int x,int y){ LL ans=0; if (num[x]==num[y]) { for (int i=x;i<=y;++i) { ans+=cub[i][t[num[x]]]; if (ans>=Mod) ans-=Mod; } return ans; } if (x==l[num[x]]) x=num[x]; else { for (int i=x;i<=r[num[x]];++i) { ans+=cub[i][t[num[x]]]; if (ans>=Mod) ans-=Mod; } x=num[x]+1; } if (y==r[num[y]]) y=num[y]; else { for (int i=l[num[y]];i<=y;++i) { ans+=cub[i][t[num[y]]]; if (ans>=Mod) ans-=Mod; } y=num[y]-1; } for (int i=x;i<=y;++i) { ans+=Cub[i][t[i]]; if (ans>=Mod) ans-=Mod; } return ans;}int main(){ scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%I64d",&a[i]); block=n/floor(sqrt(n*sz)); if (!block) ++block; tot=(n-1)/block+1; for (int i=1;i<=n;++i) { num[i]=(i-1)/block+1; if (num[i]!=num[i-1]) r[num[i-1]]=i-1,l[num[i]]=i; } r[tot]=n; init(); scanf("%d",&m); for (int i=1;i<=m;++i) { opt=getchar(); while (opt!='C'&&opt!='Q') opt=getchar(); scanf("%d%d",&x,&y); if (x>y) swap(x,y); if (opt=='C') change(x,y); else printf("%I64d\n",query(x,y)); }}
总结
卡常数技巧
①分块大小
②加法的取模改成加减
③尽量不用乘法用加减
0 0
- [SD2014集训]查询(分块+数学相关)
- [UOJ#206][Apio2016]Gap(分块+数学相关)
- [SD2016集训]Play with array(分块+双向链表)
- 数学复习(2017NOIP集训)
- [JZOJ4438] K小数查询(经典分块)
- 20160124集训Day3-数学
- 数学相关(未完成)
- 【数学建模集训系列】公交查询系统的matlab实现-只含公交的查询
- 寒假集训作业(8)——数学问题
- K小数查询:分块
- ACM-ICPC集训--数学基础知识
- 数学相关(更新ing)
- 数学相关
- 数学相关
- 数学相关
- K小数查询 分块模板
- 分块查询 缓解内存开销
- jzoj 3547. 【清华集训2014】mex 分块+莫队算法
- MapReduce:详解Shuffle过程
- GradientDrawable 可以用来通过程序方式给控件设置背景如圆角,边框等
- (4)Hadoop 添加和删除数据节点
- ansible安装配置
- 数据库隔离级别的本质解释
- [SD2014集训]查询(分块+数学相关)
- SQLite基本使用
- Shiro实战(二)
- ajax跨域请求小结
- mvc请求过程总结
- 完全背包
- 1021.Deepest Root (25)
- HttpApplication的处理管道19个事件。
- phpStudy在linux下的使用说明