BZOJ4085: [Sdoi2015]音质检测

由于这题太毒了,导致可能会被某些人卡评测,于是成了一道权限题。。。

本蒟蒻表示没钱氪金。。。

但是可以去洛谷/Vijos搞搞事。。。

但是洛谷上只能评测,题面暂时不全。。。

然而Vijos上数据范围不对,应该是洛谷上的数据范围。。。

所以没钱氪金就凑合着看吧。。。

这里附上Vijos的题面。

1958 音质检测

描述

万老板希望在新的智能音乐播放设备IPOOD中,实现对波文件音质性能的评定。

离散的波文件被考虑为长度为N的整数序列:$A_1,A_2,\cdots,A_N$​。所谓的音质性能检测,可以评定任何的一个区间范围$[L,R]$,其音质性能取决于下述评分:

$\Big\{ \sum_{L<i<R} F[A_{i-1}+1]F[A_{i+1}-1] \Big\} \mod (10^9+7)$

其中F是可归纳定义的数列,满足$F[1]=1$,$F[2]=2$且$F[k+2]=F[k+1]+aF[k]+b$对于任何$k\ge 1$成立。其中$a $和$b$为正整系数。

为了可以为用户提供更好的服务体验,并希望对给定的波文件进行修正优化。这一款设备中,还应该支持对波文件的修改。
对于给定的区间范围$[L,R]$,允许用户将$A[L]$至$A[R]$同时增加一,或同时减少一。

格式

输入格式

输入的第一行有两个正整数,波文件的总长度NN,和总的修改与询问次数QQ。

第二行有两个整数,分别表示系数aa和bb。

之后若干行,一共给出NN个正整数A_1A1​到A_NAN​,满足$1 \le A[i] \le 2*10^9$。

之后$Q$行,每行是下述三种形式之一:

$plus~L~R$:将波文件数列中下标在区间$[L,R]$内的元素每一个都加一。

$minus~L~R$:将波文件数列中下标在区间$[L,R]$内的元素每一个都减一。

$query~L~R$:询问区间$[L,R]$的音质性能评分。

修改和询问中,均保证$L\le R$,且保证$A[i]$严格大于总的修改次数加一(修改操作包括plus和minus两种)。

输出格式

输出若干行,每一行对应一次询问,输出一个整数。

样例1

样例输入1

7 7
1 0
3 4 5 6 7 8 9
query 2 4
query 3 7
plus 3 5
query 2 4
plus 4 7
query 3 7
query 1 7

样例输出1

64
1766
104
7479
7687

样例2

样例输入2

7 12
123456789 987654321
1111111111 1222222222 1333333333
1444444444 1555555555 1666666666 1777777777
query 2 4
query 3 7
plus 3 5
minus 4 6
plus 5 7
query 2 4
query 1 6
plus 4 7
minus 1 4
query 3 7
query 2 6
query 1 7

样例输出2

528103209
239947280
528103209
229970829
524160263
336413855
113033289

限制

对于15%的数据,$\(N\le 8000,Q\le 8000\)$。

对于100%的数据,$\(N\le 100000,Q\le 100000,0\le a,b\le 10^9\)$。

此外:

存在15%的数据,每一次修改的区间都是[1,N]。

还存在30%的数据,a=0,b=1。

来源

SDOI 2015 round2 day1


题解Here!

这个题简直就是道神题。。。

首先,线段树+奇奇怪怪的矩阵快速幂应该都能想到。

关键是怎么做对吧。。。

首先考虑一个性质:我们如果有数列的相邻两项$f[i],f[i+1]$。

那么用这两项向后推$k$项其线性表示系数一定。

即表示为$f[i+k]=A\times f[i]+B\times f[i+1]+C$的形式。

那么这样我们预处理这些系数就好了嘛。

注意到维护的是一个乘积的形式,那么我们要维护这个必须得维护$8$个量。

对!你没有看错!$8$个!

将其写成$3\times 3$矩阵的形式转移会比较科学。

注意$a==0$时的特判。

以上是正解。

然后某位巨佬用了$BSGS$预处理$f$函数,简直无敌了:链接

然而我表示并不能码出来,于是自己$YY$了一个方案。

思路大致差不多,但是维护的东西多了点。

我们可以用线段树维护$f[a_{i-1}],f[a_{i-1}+1],f[a_{i-1}-1],f[a_{i+1}],f[a_{i+1}+1],f[a_{i+1}-1]$以及两两乘积和。

加一的时候可以直接用递推式用保存的$f$值求出新的值。

减一的时候也可以解方程求值。

然后开始码码码。。。

好长啊。。。

记得尽量降低时间、空间复杂度,能$return$的地方尽量$return$,以免不必要的搜索导致$TLE/MLE$。

还有一件事,注意开$long\ long$!

还有一件事,做减法的时候如果减了两次,一定要先取模,再$+MOD$,再取模!不然会求出来负数。。。

还有一件事,注意线段树的边界问题,为这个我还浪费了一次提交,药丸。。。

附上炒鸡长的代码(码风较丑不要打我。。。):

#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x,i,j) a[x].data[i-1][j-1]
#define SUM(x,i,j) a[x].sum[i-1][j-1]//为了省空间只能这么干了。。。
#define ADD(x) a[x].c
#define DEL(x) a[x].d
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 300010
#define MOD 1000000007LL
using namespace std;
int n,m;
long long A,B,inv,f[MAXN][4];
struct node{
long long val[4][4];
inline void clean(){
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
val[i][j]=(i==j);
}
friend node operator *(const node x,const node y){
node ret;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++){
ret.val[i][j]=0;
for(int k=1;k<=3;k++)ret.val[i][j]=(ret.val[i][j]+x.val[i][k]*y.val[k][j]%MOD)%MOD;
}
ret.val[3][3]=1;
return ret;
}
}one,two,power[35];
struct Segment_Tree{
long long sum[3][3],data[3][3];
int c,d,l,r;
}a[MAXN<<2];
inline long long read(){
long long date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
long long mexp(long long a,long long b,long long c){
long long s=1;
while(b){
if(b&1)s=s*a%c;
a=a*a%c;
b>>=1;
}
return s;
}
node pow(long long k){
node s;
s.clean();
int i=1;
while(k){
if(k&1)s=s*power[i];
k>>=1;
i++;
}
return s;
}
void function(int i){
node s=one*pow(f[i][0]-2);
f[i][1]=s.val[1][2];f[i][2]=s.val[1][1];
}
void build(){
one.val[1][1]=2;one.val[1][2]=one.val[1][3]=1;
two.val[1][1]=two.val[1][2]=two.val[3][3]=1;
two.val[2][1]=A;two.val[3][1]=B;
for(int i=1;i<=32;i++){
power[i]=two;
two=two*two;
}
}
inline void pushup(int rt){
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++){
DATA(rt,i,j)=(DATA(LSON,i,j)+DATA(RSON,i,j))%MOD;
SUM(rt,i,j)=(SUM(LSON,i,j)+SUM(RSON,i,j))%MOD;
}
}
inline void add(int rt,int l){
for(int i=1;i<=2;i++)SUM(rt,l,i)=SUM(rt,l,i+1);
SUM(rt,l,3)=(SUM(rt,l,2)+A*SUM(rt,l,1)%MOD+B*WIDTH(rt)%MOD)%MOD;
if(l==1){
for(int i=1;i<=2;i++)
for(int j=1;j<=3;j++)
DATA(rt,i,j)=DATA(rt,i+1,j);
for(int i=1;i<=3;i++)DATA(rt,3,i)=(DATA(rt,2,i)+A*DATA(rt,1,i)%MOD+B*SUM(rt,2,i)%MOD)%MOD;
}
else{
for(int i=1;i<=3;i++)
for(int j=1;j<=2;j++)
DATA(rt,i,j)=DATA(rt,i,j+1);
for(int i=1;i<=3;i++)DATA(rt,i,3)=(DATA(rt,i,2)+A*DATA(rt,i,1)%MOD+B*SUM(rt,1,i)%MOD)%MOD;
}
}
inline void del(int rt,int l){
if(A==0){
for(int i=2;i>=1;i--)SUM(rt,l,i+1)=SUM(rt,l,i);
SUM(rt,l,1)=(SUM(rt,l,2)-B*WIDTH(rt)%MOD+MOD)%MOD;
if(l==1){
for(int i=2;i>=1;i--)
for(int j=1;j<=3;j++)
DATA(rt,i+1,j)=DATA(rt,i,j);
for(int i=1;i<=3;i++)DATA(rt,1,i)=(DATA(rt,2,i)-B*SUM(rt,2,i)%MOD+MOD)%MOD;
}
else{
for(int i=1;i<=3;i++)
for(int j=2;j>=1;j--)
DATA(rt,i,j+1)=DATA(rt,i,j);
for(int i=1;i<=3;i++)DATA(rt,i,1)=(DATA(rt,i,2)-B*SUM(rt,1,i)%MOD+MOD)%MOD;
}
return;
}
for(int i=2;i>=1;i--)SUM(rt,l,i+1)=SUM(rt,l,i);
SUM(rt,l,1)=((SUM(rt,l,3)-SUM(rt,l,2)-B*WIDTH(rt)%MOD)*inv%MOD+MOD)%MOD;
if(l==1){
for(int i=2;i>=1;i--)
for(int j=1;j<=3;j++)
DATA(rt,i+1,j)=DATA(rt,i,j);
for(int i=1;i<=3;i++)DATA(rt,1,i)=((DATA(rt,3,i)-DATA(rt,2,i)-B*SUM(rt,2,i)%MOD)*inv%MOD+MOD)%MOD;
}
else{
for(int i=1;i<=3;i++)
for(int j=2;j>=1;j--)
DATA(rt,i,j+1)=DATA(rt,i,j);
for(int i=1;i<=3;i++)DATA(rt,i,1)=((DATA(rt,i,3)-DATA(rt,i,2)-B*SUM(rt,1,i)%MOD)*inv%MOD+MOD)%MOD;
}
}
inline void pushdown_sign(int rt,int l,int c){
if(!c)return;
if(c>0)for(int i=1;i<=c;i++)add(rt,l);
else for(int i=-1;i>=c;i--)del(rt,l);
}
inline void pushdown(int rt){
if(LSIDE(rt)==RSIDE(rt))return;
ADD(LSON)+=ADD(rt);DEL(LSON)+=DEL(rt);
pushdown_sign(LSON,1,ADD(rt));pushdown_sign(LSON,2,DEL(rt));
ADD(RSON)+=ADD(rt);DEL(RSON)+=DEL(rt);
pushdown_sign(RSON,1,ADD(rt));pushdown_sign(RSON,2,DEL(rt));
ADD(rt)=DEL(rt)=0;
}
void buildtree(int l,int r,int rt){
LSIDE(rt)=l;RSIDE(rt)=r;ADD(rt)=DEL(rt)=0;
if(l==r){
for(int i=1;i<=3;i++){
SUM(rt,1,i)=f[l-1][i];
SUM(rt,2,i)=f[l+1][i];
}
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
DATA(rt,i,j)=SUM(rt,1,i)*SUM(rt,2,j)%MOD;
return;
}
int mid=LSIDE(rt)+RSIDE(rt)>>1;
buildtree(l,mid,LSON);
buildtree(mid+1,r,RSON);
pushup(rt);
}
void update_add(int l,int r,int c,int rt){
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
ADD(rt)+=c;
pushdown_sign(rt,1,c);
return;
}
pushdown(rt);
int mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update_add(l,r,c,LSON);
if(mid<r)update_add(l,r,c,RSON);
pushup(rt);
}
void update_del(int l,int r,int c,int rt){
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
DEL(rt)+=c;
pushdown_sign(rt,2,c);
return;
}
pushdown(rt);
int mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update_del(l,r,c,LSON);
if(mid<r)update_del(l,r,c,RSON);
pushup(rt);
}
long long query(int l,int r,int rt){
if(l>r)return 0;
long long ans=0;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt,3,1);
pushdown(rt);
int mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans=(ans+query(l,r,LSON))%MOD;
if(mid<r)ans=(ans+query(l,r,RSON))%MOD;
return ans;
}
void work(){
char ch[7];
int x,y,l,r;
while(m--){
scanf("%s",ch);x=read();y=read();
if(ch[0]=='p'){
l=x+1;r=y+1;
if(r>n)r=n;
if(l<=r)update_add(l,r,1,1);
l=x-1;r=y-1;
if(l<1)l=1;
if(l<=r)update_del(l,r,1,1);
}
else if(ch[0]=='m'){
l=x+1;r=y+1;
if(r>n)r=n;
if(l<=r)update_add(l,r,-1,1);
l=x-1;r=y-1;
if(l<1)l=1;
if(l<=r)update_del(l,r,-1,1);
}
else printf("%lld\n",query(x+1,y-1,1));
}
}
void init(){
n=read();m=read();A=read();B=read();
inv=mexp(A,MOD-2,MOD);
build();
for(int i=1;i<=n;i++){
f[i][0]=read();
function(i);
f[i][3]=(f[i][2]+f[i][1]*A%MOD+B)%MOD;
}
buildtree(1,n,1);
}
int main(){
init();
work();
return 0;
}

BZOJ4085: [Sdoi2015]音质检测的更多相关文章

  1. 洛谷 P3328 【[SDOI2015]音质检测】

    这题我做的好麻烦啊... 一开始想分块来着,后来发现可以直接线段树 首先考虑一个性质,我们如果有数列的相邻两项f[i]和 f[i+1]那么用这两项向后推k项其线性表示系数一定(表示为f[i+k]=a∗ ...

  2. BZOJ 4085:[Sdoi2015]quality(round 2 音质检测)(数据结构)

    居然在考场上把这道题打出来了觉得自己也是有点吊啊(虽然后面就没时间做其他题了囧而且还被卡常数了...) 题解自己写了一份TEX的就直接放上来吧.... 好啦,在谈点什么别的 什么?你在bz上TLE了? ...

  3. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  4. 详解 WebRTC 高音质低延时的背后 — AGC(自动增益控制)

    前面我们介绍了 WebRTC 音频 3A 中的声学回声消除(AEC:Acoustic Echo Cancellation)的基本原理与优化方向,这一章我们接着聊另外一个 "A" - ...

  5. dll文件32位64位检测工具以及Windows文件夹SysWow64的坑

    自从操作系统升级到64位以后,就要不断的需要面对32位.64位的问题.相信有很多人并不是很清楚32位程序与64位程序的区别,以及Program Files (x86),Program Files的区别 ...

  6. Android性能优化之利用LeakCanary检测内存泄漏及解决办法

    前言: 最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来. ...

  7. C++的内存泄漏检测

    C++大量的手动分配.回收内存是存在风险的,也许一个函数中一小块内存泄漏被重复放大之后,最后掏空内存. 这里介绍一种在debug模式下测试内存泄漏的方法. 首先在文件的开头以确定的顺序写下这段代码: ...

  8. 使用 Android Studio 检测内存泄漏与解决内存泄漏问题

    本文在腾讯技术推文上 修改 发布. http://wetest.qq.com/lab/view/63.html?from=ads_test2_qqtips&sessionUserType=BF ...

  9. iOS网络4——Reachability检测网络状态

    一.整体介绍 前面已经介绍了网络访问的NSURLSession.NSURLConnection,还有网页加载有关的webview,基本满足通常的网络相关的开发. 其实在网络开发中还有比较常用的就是网络 ...

随机推荐

  1. Effective java -- 7 通用程序设计

    第四十五条:将局部变量的作用域最小化 第四十六条:加强版for循环优于传统for循环 第四十七条:了解和使用类库书中提到了一个生成随机数的例子.正好需要. public static void mai ...

  2. zookeeper学习与实战(一)环境部署

    [背景]:最近需要做这样一件事,在一台服务器上通过客户端生成配置文件,然后需要将该配置文件实时的传输到上百台应用服务器,供应用程序读取.同时,该配置文件是不定时更新内容,只要有更新,远程应用服务器应该 ...

  3. 前端开发笔记--flex布局

    flex布局: 个人觉得flex布局比起传统布局要优先得多(主要是容易使用),缺点是IE10及以上版本才能使用,甚至某些属性只有在IE11才能使用(而且我发现凡是不兼容主要IE的坑来的多,不是说其他浏 ...

  4. MYSQL函数 Cast和convert的用法详解

    MYSQL Cast函数是非常重要的MYSQL函数,下面就将为您详细介绍MYSQL Cast函数的语法及其使用,希望能让您对MYSQL Cast函数有更多的认识. BINARY     BINARY操 ...

  5. python UDP CS demo

    UDP Communication Contents UDP Communication Sending Receiving Using UDP for e.g. File Transfers Mul ...

  6. 重拾安卓_01_安卓开发环境搭建(eclipse)

    一.下载安装Android SDK 1.下载地址 (1)官网(可FQ选择):http://developer.android.com/sdk/index.html (2)不可FQ选择:http://w ...

  7. web网页打印的方法

    WebBrowser.ExecWB的完整说明 个人感觉的:致命缺点-----------------仅仅支持ie浏览器 document.all.WebBrowser.ExecWB WebBrowse ...

  8. Mex混合编程专题一:Mex环境搭建

    使用Matlab时间长了,难免会碰到使用mex文件的经历,不管是别人的还是自己的,就比如MatConvNet(http://www.vlfeat.org/matconvnet/)使用了混合编程的技术实 ...

  9. codeforces 707B B. Bakery(水题)

    题目链接: B. Bakery 题意: 是否存在一条连接特殊和不特殊的边,存在最小值是多少; 思路: 扫一遍所有边: AC代码: #include <iostream> #include ...

  10. linux命令学习笔记(60):scp命令

    scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行 拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度.当你服务 ...