一种思维难度小但比难写的做法。
考虑钦定一段区间然后统计区间被算多少次。发现 \([l,r]\) 一共会被算 \(2^{l-2}2^{n-r-1}\) 次。注意这里把 \(2^{-1}\) 看作 \(1\)。
首先考虑如何算出 \(A(l,r)\),考虑 \(c_{i,k}\) 表示 \(\sum_{j=1}^i[a_j=k]\),然后记 \(s_i\) 表示 \(\sum_{j=1}^i[a_j=1]c_{j,0}\),即 \(s_i=A(1,i)\)。
则 \(A(l,r)=s_r-s_{l-1}-(c_{r,1}-c_{l-1,1})c_{l-1,0}\),代表把 \(s_i\) 中多出的 \(c_{l-1,0}\) 扣出去。
那么区间 \([l,r]\) 只算 \(A\) 的答案即为 \(2^{l-2}2^{n-r-1}(t_r-t_{l-1})[s_r-s_{l-1}-(c_{r,1}-c_{l-1,1})c_{l-1,0}]\)。这里 \(t_i=\sum_{j=1}^i[a_j=b_j]\)。发现贡献对于 \(l,r\) 是独立的,因此可以通过前缀和 \(O(1)\) 统计。\(B\) 的做法和 \(A\) 一样。
难写的地方是要对拆开上面的式子然后每一项分别前缀和。同时这个做法常数比较大,卡常的方法是把相同的几项并在一起并且 \(A,B\) 一起做。时间复杂度 \(O(n)\)。
const int N=50000005,P=1000000007;
int n,a[N],b[N];ll ans=0;
ll pwn,i2;
il ll fpow(ll x,ll n){ll a=1;while(n){if(n&1)a=a*x%P;x=x*x%P,n>>=1;}return a;}
il void addto(ll &x,ll y){x+=y;if(x>=P)x-=P;}
il void delto(ll &x,ll y){x-=y;if(x<0)x+=P;}il void solve(){ll s1=0,s2=0,s3=0,s4=0,s5=0,s6=0,s7=0,s8=0,t=0,s=0,c0=0,c1=0,c2=0,c3=0,res,pw1=1,pw2=pwn;forto(i,1,n){addto(s1,pw1);addto(s2,pw1*c0%P);addto(s3,pw1*c2%P);addto(s4,pw1*(c1*c0%P+c3*c2%P-s+P)%P);addto(s5,pw1*t%P);addto(s6,pw1*t%P*c0%P);addto(s7,pw1*t%P*c2%P);addto(s8,pw1*t%P*(c1*c0%P+c3*c2%P-s+P)%P);t+=(a[i]!=b[i]);if(a[i])addto(s,c0),c1++;else c0++;if(!b[i])addto(s,c2),c3++;else c2++;res=0;addto(res,s1*t%P*s%P);delto(res,s2*t%P*c1%P);delto(res,s3*t%P*c3%P);addto(res,s4*t%P);delto(res,s5*s%P);addto(res,s6*c1%P);addto(res,s7*c3%P);delto(res,s8);addto(ans,res*pw2%P);if(i>1)pw1=2*pw1%P;if(i<n-1)pw2=i2*pw2%P;}
}unsigned ll f[800005];
il void init(int a[]){unsigned ll x=read(),y=read(),z=read();f[1]=read(),f[2]=read();forto(i,3,(n-1)/64+3)f[i]=f[i-2]*x+f[i-1]*y+z;forto(i,1,n)a[i]=(f[(i-1)/64+3]>>((i-1)%64))&1;
}signed main(){n=read();int op=read();pwn=1;forto(i,1,n-2)pwn=2*pwn%P;i2=fpow(2,P-2);if(!op)forto(i,1,n)a[i]=read(),b[i]=read();else init(a),init(b);solve();printf("%lld\n",ans);return 0;
}