[CF718C] Sasha and Array
18.10.30模拟赛T2。
模拟赛现场切了这个题......但是这道题有点卡常啊,时限3秒差点没过。
老师的电脑上能过,自己的机器上过不了......
我写的东西常数还是太大了QAQ
题解:
这道题思路比较简单。
区间的操作肯定是线段树维护一下。
要是用线段树修改ai,每次查询的时候还得暴力算fib。
我们考虑用线段树维护fib(ai)。
这样查询比较容易了,但是修改就不能直接区间加上一个数了。
事实上很难仅仅维护一个fib(ai)。
干脆维护[ fib(ai) fib(ai-1) ]这个矩阵。
每次修改的时候乘上转移矩阵的x次幂就好了。
由于要统计区间和,我们也要维护区间和。
显然矩阵乘完相加和先加再乘,结果是一样的。
所以......就再写一个矩阵相加。
通过这道题发现unsigned long long比long long快很多......
long long 3.1s的点,unsigned long long只需要跑2.2s左右。
而矩阵乘法加个取址也不过就快0.1s。
所以unsigned这个优化很强啊......
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int mod=1000000007; 7 8 struct matrix 9 { 10 ll a[2][2]; 11 }bs,unt; 12 13 bool same(matrix &q,matrix &w) 14 { 15 if(q.a[0][0]!=w.a[0][0])return 0; 16 if(q.a[0][1]!=w.a[0][1])return 0; 17 if(q.a[1][0]!=w.a[1][0])return 0; 18 if(q.a[1][1]!=w.a[1][1])return 0; 19 return 1; 20 } 21 22 matrix mul(matrix &q,matrix &w) 23 { 24 matrix rt; 25 for(int i=0;i<=1;i++) 26 { 27 for(int j=0;j<=1;j++) 28 { 29 rt.a[i][j]=0; 30 for(int k=0;k<=1;k++) 31 rt.a[i][j]=(rt.a[i][j]+q.a[i][k]*w.a[k][j]%mod)%mod; 32 } 33 } 34 return rt; 35 } 36 37 matrix add(matrix &ret,matrix &q,matrix &w) 38 { 39 for(int i=0;i<=1;i++) 40 for(int j=0;j<=1;j++) 41 ret.a[i][j]=(q.a[i][j]+w.a[i][j])%mod; 42 } 43 44 matrix ksm(matrix b,int p) 45 { 46 if(!p)return unt; 47 matrix rt=b; 48 p--; 49 while(p) 50 { 51 if(p&1)rt=mul(rt,b); 52 b=mul(b,b); 53 p>>=1; 54 } 55 return rt; 56 } 57 58 int n,m; 59 int st[100005]; 60 int lb[400005],rb[400005]; 61 matrix sum[400005],lz[400005]; 62 63 void pushup(int p) 64 { 65 add(sum[p],sum[p<<1],sum[p<<1|1]); 66 } 67 68 void build(int p,int l,int r) 69 { 70 lb[p]=l,rb[p]=r; 71 lz[p]=unt; 72 if(l==r) 73 { 74 sum[p]=ksm(bs,st[l]-1); 75 return; 76 } 77 int mid=(l+r)>>1; 78 build(p<<1,l,mid); 79 build(p<<1|1,mid+1,r); 80 pushup(p); 81 } 82 83 void pushdown(int p) 84 { 85 if(same(unt,lz[p]))return; 86 sum[p<<1]=mul(sum[p<<1],lz[p]); 87 sum[p<<1|1]=mul(sum[p<<1|1],lz[p]); 88 lz[p<<1]=mul(lz[p<<1],lz[p]); 89 lz[p<<1|1]=mul(lz[p<<1|1],lz[p]); 90 lz[p]=unt; 91 } 92 93 void mul(int p,int l,int r,matrix &v) 94 { 95 if(l>r)return; 96 if(lb[p]>=l&&rb[p]<=r) 97 { 98 sum[p]=mul(sum[p],v); 99 lz[p]=mul(lz[p],v); 100 return; 101 } 102 pushdown(p); 103 int mid=(lb[p]+rb[p])>>1; 104 if(l<=mid)mul(p<<1,l,r,v); 105 if(r>mid)mul(p<<1|1,l,r,v); 106 pushup(p); 107 } 108 109 ll ask(int p,int l,int r) 110 { 111 if(l>r)return 0; 112 if(lb[p]>=l&&rb[p]<=r) 113 { 114 return sum[p].a[0][0]; 115 } 116 ll ret=0; 117 pushdown(p); 118 int mid=(lb[p]+rb[p])>>1; 119 if(l<=mid)ret+=ask(p<<1,l,r); 120 if(r>mid)ret+=ask(p<<1|1,l,r); 121 ret=ret%mod; 122 return ret; 123 } 124 125 int read() 126 { 127 int ret=0;char cc=getchar(); 128 while(cc<'0'||cc>'9')cc=getchar(); 129 while(cc>='0'&&cc<='9')ret=ret*10+cc-'0',cc=getchar(); 130 return ret; 131 } 132 133 int main() 134 { 135 bs.a[0][0]=1; 136 bs.a[0][1]=1; 137 bs.a[1][0]=1; 138 bs.a[1][1]=0; 139 unt.a[0][0]=1; 140 unt.a[0][1]=0; 141 unt.a[1][0]=0; 142 unt.a[1][1]=1; 143 scanf("%d%d",&n,&m); 144 for(int i=1;i<=n;i++)scanf("%d",&st[i]); 145 build(1,1,n); 146 for(int i=1;i<=m;i++) 147 { 148 int op; 149 scanf("%d",&op); 150 if(op==1) 151 { 152 int l=read(),r=read(),x=read(); 153 //scanf("%d%d%d",&l,&r,&x); 154 matrix tmp=ksm(bs,x); 155 mul(1,l,r,tmp); 156 } 157 if(op==2) 158 { 159 int l=read(),r=read(); 160 //scanf("%d%d",&l,&r); 161 ll ans=ask(1,l,r); 162 printf("%I64d\n",ans); 163 } 164 } 165 return 0; 166 }