Codeforces Round #373 (Div. 2)
A,B,C傻逼题,就不说了。
E题:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 const int maxn=100005,mod=1000000007; 8 typedef long long int64; 9 int n,m,fuck[maxn<<2]; 10 int64 a[maxn],s1[maxn<<2],s2[maxn<<2]; 11 struct Matrix{ 12 int n,m; 13 int64 a[2][2]; 14 void clear(){for (int i=0;i<2;i++)for (int j=0;j<2;j++)a[i][j]=0;} 15 }wn,lazy[maxn<<2],a0,t1,t2,b; 16 Matrix operator *(Matrix x,Matrix y){ 17 Matrix ans; ans.n=x.n,ans.m=y.m; 18 ans.clear(); int N=ans.n,M=ans.m; 19 for (int i=0;i<N;i++){ 20 for (int j=0;j<M;j++){ 21 for (int k=0;k<x.m;k++){ 22 ans.a[i][j]=(ans.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod; 23 } 24 } 25 } 26 return ans; 27 } 28 Matrix qpow(Matrix x,int64 y){ 29 if (y==0) return wn; 30 if (y==1) return x; 31 Matrix d=qpow(x,y/2); d=d*d; 32 if (y&1) return d*x; 33 else return d; 34 } 35 void build(int k,int l,int r){ 36 lazy[k]=wn; fuck[k]=-1; 37 if (l==r) return; 38 int mid=(l+r)>>1; 39 build(k*2,l,mid),build(k*2+1,mid+1,r); 40 } 41 void pushdown(int k,Matrix x){ 42 Matrix y=x; 43 int64 oy=s1[k],zx=s2[k],A,B,C; 44 t1=a0*x; A=t1.a[0][0]; x=x*b; 45 t1=a0*x; B=t1.a[0][0]; x=x*b; 46 t1=a0*x; C=t1.a[0][0]; 47 s1[k]=(oy*A%mod+zx*B%mod)%mod; 48 s2[k]=(oy*B%mod+zx*C%mod)%mod; 49 if (fuck[k]!=-1){lazy[k]=lazy[k]*y,lazy[k]=lazy[k]*b;} 50 else lazy[k]=y; 51 fuck[k]=1; 52 } 53 void insert(int k,int l,int r,int x,int64 y1,int64 y2){ 54 if (l==r&&r==x){s1[k]=y1%mod,s2[k]=y2%mod;return;} 55 int mid=(l+r)>>1; 56 if (x<=mid) insert(k*2,l,mid,x,y1,y2); 57 else insert(k*2+1,mid+1,r,x,y1,y2); 58 s1[k]=(s1[k*2]+s1[k*2+1])%mod,s2[k]=(s2[k*2]+s2[k*2+1])%mod; 59 } 60 void change(int k,int l,int r,int x,int y,Matrix t){ 61 if (fuck[k]!=-1){ 62 if (l!=r){pushdown(k*2,lazy[k]),pushdown(k*2+1,lazy[k]);} 63 lazy[k]=wn; fuck[k]=-1; 64 } 65 if (l>=x&&r<=y){pushdown(k,t);return;} 66 int mid=(l+r)>>1; 67 if (x<=mid) change(k*2,l,mid,x,y,t); 68 if (y>mid) change(k*2+1,mid+1,r,x,y,t); 69 s1[k]=(s1[k*2]+s1[k*2+1])%mod,s2[k]=(s2[k*2]+s2[k*2+1])%mod; 70 } 71 int64 query(int k,int l,int r,int x,int y){ 72 if (fuck[k]!=-1){ 73 if (l!=r){pushdown(k*2,lazy[k]),pushdown(k*2+1,lazy[k]);} 74 lazy[k]=wn; fuck[k]=-1; 75 } 76 if (l>=x&&r<=y) return s2[k]%mod; 77 int mid=(l+r)>>1; int64 temp=0; 78 if (x<=mid) temp=(temp+query(k*2,l,mid,x,y))%mod; 79 if (y>mid) temp=(temp+query(k*2+1,mid+1,r,x,y))%mod; 80 return temp; 81 } 82 int main(){ 83 scanf("%d%d",&n,&m); a0.clear(),t1.clear(),b.clear(),wn.clear(); 84 a0.n=1,a0.m=2; a0.a[0][0]=0,a0.a[0][1]=1; 85 wn.n=2,wn.m=2; 86 for (int i=0;i<2;i++) 87 for (int j=0;j<2;j++){ 88 if (i==j) wn.a[i][j]=1; 89 else wn.a[i][j]=0; 90 } 91 build(1,1,n); 92 b.n=b.m=2; 93 for (int i=0;i<2;i++){ 94 for (int j=0;j<2;j++){ 95 if (!i&&!j) b.a[i][j]=0; 96 else b.a[i][j]=1; 97 } 98 } 99 memset(s1,0,sizeof(s1)); 100 memset(s2,0,sizeof(s2)); 101 for (int i=1;i<=n;i++){ 102 scanf("%I64d",&a[i]); 103 t1=a0*qpow(b,a[i]); 104 t2=a0*qpow(b,a[i]-1); 105 insert(1,1,n,i,t2.a[0][0],t1.a[0][0]); 106 } 107 for (int type,l,r,x;m;m--){ 108 scanf("%d%d%d",&type,&l,&r); 109 if (type==1){ 110 scanf("%d",&x); 111 t1=qpow(b,x-1); 112 change(1,1,n,l,r,t1); 113 }else{printf("%I64d\n",query(1,1,n,l,r)%mod);} 114 } 115 return 0; 116 }
链接:http://codeforces.com/contest/719/problem/E
题目大意:给定一个长度为n的序列ai,m个操作,有以下两种操作,1种是把l~r这一段数加上一个数x,另1种是询问l~r的f[ai]之和,f[i]为斐波那契数列的第i项,令f[1]=f[2]=1,f[i]=f[i-2]+f[i-1](i>2). n,m<=10^5 , 1<=ai,x<=10^9;
做法:这题显然是要用线段树和矩阵快速幂,但是是区间修改不好维护,但是对于斐波那契数列有个结论就是f[n+m]=f[n-1]*f[m]+f[n]*f[m+1],有了这个就很好做了,如下:
f(a+x) = f(x+1)f(a) + f(x)f(a-1)
f(a-1+x) = f(x-1)f(a-1) + f(x)f(a)
令s1(l,r)为区间内所有f(a[i])的和
令s2(l,r)为区间内所有f(a[i]-1)的和
然后线段树维护这两个就行了,每次计算某个f(x)的值就拿矩阵快速幂(8*logn)。
这样的做法是nlogn^2的,加上线段树的常数是过不了的,我们得考虑矩阵乘法那一部分,我们真的需要在每次传标记的时候都用logn的时间来计算f(x)吗,显然是不需要的,我们只要把lazy标记设为一个矩阵即可,为b^x(令b为用矩阵乘法求斐波那契数列时候的矩阵),合并标记的时候就把这个矩阵乘一下即可,总时间复杂度降为了nlogn,能过。这题首先用结论把问题转化为了支持区间修改,再利用了每次计算的重复,巧妙地把lazy标记定为矩阵,进一步降低时间复杂度,一个好题。