[CF718C] Sasha and Array

18.10.30模拟赛T2。

CF题目传送门

洛谷传送门

模拟赛现场切了这个题......但是这道题有点卡常啊,时限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
",ans);
163         }
164     }
165     return 0;
166 }
Code
原文地址:https://www.cnblogs.com/eternhope/p/9877868.html