zoukankan      html  css  js  c++  java
  • BZOJ4085: [Sdoi2015]音质检测

    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$对于任何$kge 1$成立。其中$a $和$b$为正整系数。

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

    格式

    输入格式

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

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

    之后若干行,一共给出NN个正整数A_1A1A_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]$的音质性能评分。

    修改和询问中,均保证$Lle 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%的数据,$(Nle 8000,Qle 8000)$。

    对于100%的数据,$(Nle 100000,Qle 100000,0le a,ble 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 imes f[i]+B imes f[i+1]+C$的形式。

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

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

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

    将其写成$3 imes 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
    ",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;
    }
    
  • 相关阅读:
    PHP导出sql文件
    BugScan插件编写高(gǎo)级(jī)教程
    php父级目录文件包函问题
    检测web服务器指定位置大文件是否存在
    解决Linux关闭SSH,终端后运行程序终止问题(包括后台)
    Python Matplotlib绘图库 安装
    校园网突围之路由器开wifi__windows版
    [openwrt 项目开发笔记]: 传送门
    [Openwrt 项目开发笔记]:PHP+Nginx安装(七)
    [Openwrt 项目开发笔记]:MySQL配置(六)
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9623294.html
Copyright © 2011-2022 走看看