T1
题目:
【题目描述】
现有给定一个序列a_0,a_1,.....a_(n-1)共n项以及m个操作。操作分成以下三类:
0: 将区间[l,r]中的数加上一个值x
1: 将区间[l,r]中的数乘上-1
2: 询问区间[l,r]中的数的绝对值之和
编程实现以上操作。
【输入格式】
第一行两个数n,m,分别表示序列的长度和操作的个数
第二行n个数,第i个数表示a_(i-1)
第三至m+2行,每行采取下列形式之一:
0 l r x (表示第0种操作)
1 l r (表示第1种操作)
2 l r (表示第2种操作)
l,r,x意义如题目描述中所述。
【输出格式】
共k行(其中k是第2种操作的个数),第i行有且仅有一个数,表示第i次第2种操作的答案。
【样例输入】
4 4
-2 -1 0 1
2 0 3
1 1 3
0 0 1 2
2 0 2
【样例输出】
4
3
【时空限制与数据约束】
时间:3s 空间:256MB
对于40%的数据,n,m<=10000
对于100%的数据,n,m<=100000
数据保证所有时刻序列中的数的绝对值总和不会超过64位有符号整形范围。
题解:
乍一看以为是水题……写了一个多小时Seg套Splay发现调不出来……oh,fxxk!然后就mengbier了= =。
zyf大佬使用吉司机线段树思想?(这是什么?)
题解是分块233,真是妙啊。
当时一心想怎么用线段树维护233,没有考虑用分块/莫队……emmmm,真是
改起来也十分不方便……真的很naive……
考虑如何维护,因为*-1实际上绝对值不会改变只是每个值从$now[x]=a[x]+add[bel[x]]$改变为$-now[x]$,但以后给该元素+add就会变为-add,画个图就明白了,这样搞定了操作0。
然后对于*-1的维护(当然是两边的啦),假设这个块被标记了奇数次-1,那么实际每个数值均为当前记录的值的相反数,但是我们又有一部分变为了偶数次-1,发现假设块的add不变,我们直接给这几个值*-1是错的,(列列式子就明白),那么处理这个问题有两种方式,1是块里每个元素+add再乘-1,然后把add清空,再把部分修改的值*-1,重建这个块,2是给修改元素+add*2,再*-1。第一个很好理解,第二个化化式子就明白了。
当然由于维护块内答案需要二分,所以要把块设的小一点。
代码:

1 #include "bits/stdc++.h"
2
3 using namespace std;
4
5 typedef long long ll;
6
7 inline int read(){
8 int s=0,k=1;char ch=getchar();
9 while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar();
10 while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar();
11 return s*k;
12 }
13
14
15 inline ll readll(){
16 ll s=0,k=1;char ch=getchar();
17 while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar();
18 while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar();
19 return s*k;
20 }
21
22 const int N=1e5+10;
23
24
25 ll a[N],ans[N],mo[N],b[1005][202],sum[1005][205];
26
27 bool rev[N];
28
29 int n,m,leth,bel[N],vis[N],L[N],R[N];
30
31 inline void build(int op,int l,int r){
32 int i;
33 memcpy(b[op],a+l,sizeof b[op]);
34 sort(b[op],b[op]+r-l+1);
35 memcpy(sum[op],b[op],sizeof sum[op]);
36 ans[op]=abs(b[op][0]+mo[op]);
37 for (i=1;i+l<=r;++i)
38 sum[op][i]+=sum[op][i-1],ans[op]+=abs(b[op][i]+mo[op]);
39 vis[op]=0;
40 }
41
42 inline void update(int l,int r,int lk,int rk,ll add){
43 int i;
44 if(lk==rk) {
45 if(rev[lk]) add=-add;
46 for (i=l;i<=r;++i) a[i]+=add;
47 build(lk,L[lk],R[lk]);
48 }else {
49 ll pl;
50 if(rev[lk]) pl=-add;else pl=add;
51 for (i=l;i<=R[lk];++i) a[i]+=pl;
52 build(lk,L[lk],R[lk]);
53 if(rev[rk]) pl=-add;else pl=add;
54 for (i=L[rk];i<=r;++i) a[i]+=pl;
55 build(rk,L[rk],R[rk]);
56 for (i=lk+1;i<rk;++i) mo[i]+=(rev[i]?-add:add),vis[i]=true;
57 }
58 }
59
60 inline void sigh(int l,int r,int lk,int rk){
61 int i;
62 if(lk==rk) {
63 for (i=l;i<=r;++i) a[i]=-(a[i]+2*mo[lk]);
64 build(lk,L[lk],R[lk]);
65 }else {
66 for (i=l;i<=R[lk];++i) a[i]=-(a[i]+2*mo[lk]);
67 build(lk,L[lk],R[lk]);
68 for (i=L[rk];i<=r;++i) a[i]=-(a[i]+2*mo[rk]);
69 build(rk,L[rk],R[rk]);
70 for (i=lk+1;i<rk;++i) rev[i]^=1;
71 }
72 }
73
74 inline ll query (int op){
75 int l=-1,r=R[op]-L[op]+1,mid;
76 while(l+1<r){
77 int mid=l+r>>1;
78 if(b[op][mid]+mo[op]>=0) r=mid;
79 else l=mid;
80 }
81 vis[op]=0;
82 ans[op]=(sum[op][R[op]-L[op]]-sum[op][l])+mo[op]*(R[op]-l-L[op])
83 -((l+1)*mo[op]+sum[op][l]);
84 return ans[op];
85 }
86
87 inline ll query (int l,int r,int lk,int rk){
88 ll ret=0;int i;
89 if(lk==rk)
90 for (i=l;i<=r;++i) ret+=abs(a[i]+mo[lk]);
91 else {
92 for (i=l;i<=R[lk];++i) ret+=abs(a[i]+mo[lk]);
93 for (i=L[rk];i<=r;++i) ret+=abs(a[i]+mo[rk]);
94 for (i=lk+1;i<rk;++i)
95 if(!vis[i]) ret+=ans[i];
96 else ret+=query(i);
97 }
98 return ret;
99 }
100
101 int main(){
102 scanf("%d%d",&n,&m);leth=100;
103 for (int i=1;i<=n;++i){
104 a[i]=readll();
105 bel[i]=(i-1)/leth;
106 L[bel[i]]?0:L[bel[i]]=i;
107 R[bel[i]]=i;
108 b[bel[i]][i-bel[i]*leth-1]=a[i];
109 }
110 register int i,j;
111
112 for (i=0;i<=bel[n];++i){
113 sort(b[i],b[i]+R[i]-L[i]+1);
114 memcpy(sum[i],b[i],sizeof (sum[i]));
115 ans[i]=abs(b[i][0]);
116 for (j=1;j+L[i]<=R[i];++j) sum[i][j]+=sum[i][j-1],ans[i]+=abs(b[i][j]);
117 }
118 ll x;
119 int type,l,r;
120 int tot=0;
121 while (m--){
122 type=read(),l=read()+1,r=read()+1;
123 if(!type)
124 x=read(), update(l,r,bel[l],bel[r],x);
125 else if(type&1) sigh(l,r,bel[l],bel[r]);
126 else printf("%lld\n",query(l,r,bel[l],bel[r]));
127 }
128 }
T2
题目:
【题目描述】
fibonotci序列定义为下:
F[n] = s[n-1]F[n-1] + s[n-2]F[n-2] (n >= 2)。
F[0]=0,F[1]=1。
其中s是一个循环长度为n的循环数组,即满足s[i] = s[i % n]。
不过,s这个数组被熊孩子修改了几个位置,他把s中的第j个位置修改为了vj,也就是说,对于位置j,s[j] = v[j](j >= n)。
请你在熊孩子修改之后,求出F[k]对P取模的结果。
【输入】
第一行两个整数k,P。
接下来一行一个整数n,接下来一行n个整数,表示s[i]。
再接下来一行一个整数m,表示熊孩子的修改。
接下来m行,每行两个整数j,v[j],表示熊孩子做的修改,除修改位置之外的位置i,满足,s[i] = s[I % n](I >= n)
【输出】
输出一个整数,表示答案。
【样例输入】
10 8
3
1 2 1
2
7 3
5 4
【样例输出】
4
【数据范围】
对于20%的数据,m = 0
对于60%的数据,k <= 10^6
对于100%的数据,n,m <= 50000, 0 <= K <= 10^18, 1 <= P <= 10^9,
1 <= s[i], v[j] <= 10^9, n <= j <= 10^18,数据保证j互不相同。
题解:
(还是仿宋好看
考试花了3h打+调,最后还是交了暴力。
考虑没有熊孩子。
可以发现,其中任意一个元素$f(x)$可以表示成关于$a*f_{0}+b*f_{1}$的一个表达式。
进一步想,对于$f_{x}$必然可以用$Af_{y}+Bf_{y+1},y<x$来表达。
深层思考循环数组,可以知道$f_{x}=Af_{y}+Bf_{y+1}$,若$y%n==z$,且$x-y$的值不变,会发现对任意的满足上式的系数$A、B$其实是不会改变的,而且我们发现这个系数$A,B$从$y,y+1$到$x,x+1$再到$z,z+1$的和$y,y+1$到$z,z+1$的系数是有关的,很容易得到一个表达式,而且发现可以矩阵乘。
然后对于维护系数,我们发现可以直接维护(0,1)递推到[1,n+1]的系数,这个用线段树来。
剩下就是有熊孩子的情况,我们直接矩阵乘优化,跑的有熊孩子前一个位置的二元组(x,x+1),(x+1)上有熊孩子,再用递推式暴力走过这个熊孩子。
细节很多,就不细说了。
不得不说,循环展开快3倍……
代码:

1 #include "bits/stdc++.h"
2
3 using namespace std;
4
5 typedef long long ll;
6
7 inline int read(){
8 int s=0,k=1;char ch=getchar();
9 while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar();
10 while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar();
11 return s*k;
12 }
13
14
15 const int N=50005;
16
17 int n,m,p,s[N];
18
19 ll k;
20
21 struct Matrix{
22 ll a[2][2];
23 Matrix(){memset(a,0,sizeof a);}
24 Matrix(int A,int b,int c,int d){
25 a[0][0]=A,a[0][1]=b,a[1][0]=c,a[1][1]=d;
26 }
27 friend Matrix operator *(Matrix a,Matrix b){
28 Matrix c;
29 c.a[0][0]=(1ll*a.a[0][0]*b.a[0][0]+1ll*a.a[0][1]*b.a[1][0])%p;
30 c.a[0][1]=(1ll*a.a[0][0]*b.a[0][1]+1ll*a.a[0][1]*b.a[1][1])%p;
31 c.a[1][0]=(1ll*a.a[1][0]*b.a[0][0]+1ll*a.a[1][1]*b.a[1][0])%p;
32 c.a[1][1]=(1ll*a.a[1][0]*b.a[0][1]+1ll*a.a[1][1]*b.a[1][1])%p;
33
34 return c;
35 }
36 friend Matrix operator ^(Matrix a,ll b){
37 Matrix ans;
38 for (int i=0;i<2;++i) ans.a[i][i]=1;
39 for (;b;b>>=1,a=a*a)
40 if(b&1) ans=ans*a;
41 return ans;
42 }
43 };
44
45 struct Tree{
46 Matrix g;
47 }tree[N*4];
48
49 #define lc(x) (x<<1)
50 #define rc(x) (x<<1|1)
51
52 inline void build(int u,int l,int r){
53 if(l==r) {
54 tree[u].g=Matrix(0,1,s[l],s[l+1]);
55 return ;
56 }
57 int mid=l+r>>1;
58 build(lc(u),l,mid);
59 build(rc(u),mid+1,r);
60 tree[u].g=tree[rc(u)].g*tree[lc(u)].g;
61 }
62
63 inline Matrix query(int u,int l,int r,int x,int y){
64 if(x>y) return Matrix(1,0,0,1);
65 if(x<=l&&r<=y) return tree[u].g;
66 int mid=l+r>>1;
67 Matrix ret=Matrix(1,0,0,1);
68 if(y>mid) ret=ret*query(rc(u),mid+1,r,x,y);
69 if(x<=mid) ret=ret*query(lc(u),l,mid,x,y);
70
71 return ret;
72 }
73
74 struct node{
75 ll id;int v;
76 friend bool operator <(node a,node b){
77 return a.id<b.id;
78 }
79 }bc[N];
80
81 map<ll,int> mp;
82
83 int main(){
84 scanf("%lld",&k),p=read();
85 n=read();register int i=0,j;
86 for (;i<n;++i) s[i]=read()%p;
87 s[n]=s[0];
88 build(1,0,n-1);
89 m=read();
90 for (i=1;i<=m;++i)
91 scanf("%lld",&bc[i].id),bc[i].v=read()%p;
92 sort(bc+1,bc+m+1);
93 while (bc[m].id>=k) --m;
94 if(bc[m].id!=k-1)
95 bc[++m]=(node){k-1,s[(k-1)%n]};
96 Matrix ans=Matrix(1,0,0,0);
97 int x=1,y=0,tt,t1,t2,nowa;
98 ll now,to,t;
99 Matrix e;
100 for (i=1,now=0;i<=m;){
101 ans=Matrix(y,0,x,0);
102 to=bc[i].id-2,nowa=now%n;
103 e=query(1,0,n-1,0,nowa-1)*query(1,0,n-1,nowa,n-1);
104 ans=(e^((to-now)/n))*ans;
105 now+=n*((to-now)/n);
106 if(to/n==now/n) e=query(1,0,n-1,nowa,to%n);
107 else e=query(1,0,n-1,0,to%n)*query(1,0,n-1,nowa,n-1);
108 ans=e*ans,mp.clear(),y=ans.a[0][0],x=ans.a[1][0];
109
110 mp[bc[i].id]=bc[i].v;
111
112 for (j=i+1;j<=m;++j)
113 if(bc[j].id>bc[j-1].id+2) break;
114 else mp[bc[j].id]=bc[j].v;
115 t=max(bc[i].id+1,now+2);
116 t1=(t-1)%n,t2=(t-2)%n,tt;
117 for (;t<=bc[j-1].id+2;++t,++t1,++t2) {
118 tt=1ll*x*(mp.count(t-1)?mp[t-1]:s[t1])%p+1ll*y*(mp.count(t-2)?mp[t-2]:s[t2])%p;
119 y=x,x=tt%p;
120 (t1^n)?0:t1=0;
121 (t2^n)?0:t2=0;
122 }
123 now=t-2;
124 i=j;
125 }
126
127 printf("%d\n",y);
128 }
T3
题目:
【题目描述】
现有一个n*m的棋盘,上面有c个格子里有蟑螂药(蟑螂不能在上面行走),有d个格子里有蟑螂食分发器(分发器可以始终让这个格子上具有蟑螂食)。现有足够多的蟑螂要在棋盘上游走(每时每刻蟑螂都必须在行走,只可走向有公共边的格子),每只蟑螂的路线都是回路,蟑螂的路线互不相交。为了不让蟑螂食腐烂,需要让每个分发器都有一只蟑螂经过。现在问有几种符合以上条件的安排方案(注意在没有蟑螂食的时候,一只蟑螂都不放也是一种方案)。
【输入格式】
第一行四个数n,m,c,d,如题目描述所述。
如果c不为0,则第二至c+1行每行两个数表示含有蟑螂药的格子的坐标。
如果d不为0,则第c+2至c+d+1行每行两个数表示含有蟑螂食分发器的格子的坐标。
【输出格式】
第一行有且仅有一个数,表示方案数对1e9+7取模的结果。
【样例输入】
2 4 0 1
1 1
【样例输出】
4
【时空限制与数据约束】
时间:2s 空间:256MB
对于20%的数据,n<=6
对于40%的数据,n<=1e6
对于40%的数据,c=d=0
对于100%的数据,1<=n<=1e18,1<=m<=4,0<=c<=15,0<=d<=15
题解:
由于题目太过恶心,所以考试时候并没有想++。然而发现是最水的题……
矩阵乘+插头DP。由于之前老师在上一场以前说,上一场要考插头DP,然而并没有考,于是我调侃那天数位DP为“老师该不会认为这是矩阵乘+插头DP吧”。所以老师确实是这么认为的……有着些许的迷茫
会插头基本看到就知道是SB题,就是写起来有点麻烦……
早知道就先做这道题了……
代码:

1 #include "bits/stdc++.h"
2
3 #define int long long
4
5 using namespace std;
6
7 inline int read(){
8 int s=0,k=1;char ch=getchar();
9 while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar();
10 while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar();
11 return s*k;
12 }
13
14 const int mod=1e9+7,N=1e4+10;
15
16 typedef long long ll;
17
18 map<int,int> id;
19
20 int large,rid[20];
21
22 struct Matrix{
23 int a[20][20];
24 Matrix () {memset(a,0,sizeof a);}
25 friend Matrix operator *(Matrix a,Matrix b){
26 Matrix c;
27 for (int i=1;i<=large;++i)
28 for (int j=1;j<=large;++j)
29 for (int k=1;k<=large;++k)
30 c.a[i][j]=(c.a[i][j]+a.a[i][k]*1ll*b.a[k][j]%mod)%mod;
31 return c;
32 }
33
34 friend Matrix operator ^(Matrix a,ll b){
35 Matrix ans;
36 for (int i=1;i<=large;++i) ans.a[i][i]=1;
37 for (;b;b>>=1,a=a*a)
38 if(b&1) ans=ans*a;
39 return ans;
40 }
41 }e;
42
43 int bit[15];
44
45 int tot[2],stk[2][N],h[N],t,dp[2][N],mp[100][10],n,m,c,d;
46
47 inline void add(int s,ll val){
48 int pos=s%N;
49 while (h[pos]!=-1){
50 if(stk[t][h[pos]]==s) {
51 dp[t][h[pos]]+=val;
52 if(dp[t][h[pos]]>=mod)
53 dp[t][h[pos]]%=mod;
54 return ;
55 }
56 ++pos;
57 if(pos==N) pos=0;
58 }
59 dp[t][++tot[t]]=val;
60 h[pos]=tot[t];
61 stk[t][tot[t]]=s;
62 }
63
64 inline void insert(int i,int j){
65 t^=1;tot[t]=0;
66 memset(h,-1,sizeof(h));
67 register int k;
68 for(k=1;k<=tot[t^1];++k){
69 int s=stk[t^1][k];
70 ll val=dp[t^1][k];
71 int p=(s>>bit[j-1])&3,q=(s>>bit[j])&3;
72 if(!mp[i][j]){if(!p&&!q) add(s,val);
73 }else if(!p&&!q){
74 if((~mp[i][j])&2) add(s,val);
75 if(mp[i][j+1]&&mp[i+1][j]){
76 s+=(1<<bit[j-1])+(1<<bit[j]+1);
77 add(s,val);
78 }
79 }else if(!p&&q){
80 if(mp[i][j+1]) add(s,val);
81 if(mp[i+1][j]){
82 s+=(q<<bit[j-1])-(q<<bit[j]);
83 add(s,val);
84 }
85 }else if(!q&&p){
86 if(mp[i+1][j]) add(s,val);
87 if(mp[i][j+1]){
88 s+=(p<<bit[j])-(p<<bit[j-1]);
89 add(s,val);
90 }
91 }else if(p+q==2){
92 int b=1;
93 for(int a=j+1;a<=m;++a){
94 int v=(s>>bit[a])&3;
95 if (v==1) b++;
96 if (v==2) b--;
97 if (!b){
98 s-=(1<<bit[a]);
99 break;
100 }
101 }
102 s-=(1<<bit[j-1])+(1<<bit[j]);
103 add(s,val);
104 }
105 else if (p+q==4){
106 int b=1;
107 for(int a=j-2;a;--a){
108 int v=(s>>bit[a])&3;
109 if (v==2) b++;
110 if (v==1) b--;
111 if(!b){
112 s+=(1<<bit[a]);
113 break;
114 }
115 }
116 s-=(1<<bit[j-1])+(1<<bit[j])<<1;
117 add(s,val);
118 }else if(p+q==3){
119 s^=(p<<bit[j-1])|(q<<bit[j]);
120 add(s,val);
121 }
122 }
123 }
124
125 inline void DP(int beg,int val,int level){
126 t=0;
127 tot[0]=1,dp[t][1]=val,stk[t][1]=beg;
128 register int i,j,k;
129 for (i=1;i<=level;++i){
130 for (j=1;j<=tot[t];++j) stk[t][j]<<=2;
131 for (j=1;j<=m;++j)
132 insert(i,j);
133 }
134 }
135
136 struct node {
137 ll x,y;int type;
138 friend bool operator <(node a,node b){
139 return a.x<b.x||(a.x==b.x&&a.y<b.y);
140 }
141 }p[50];
142
143 int all;
144
145 int val[20];
146
147 inline void Get_ans(int level){
148 tot[0]=large;
149 t=0;
150 for (int i=1;i<=large;++i)
151 stk[t][i]=rid[i],dp[t][i]=val[i];
152 register int i,j,k;
153 for (i=1;i<=level;++i){
154 for (j=1;j<=tot[t];++j) stk[t][j]<<=2;
155 for (j=1;j<=m;++j)
156 insert(i,j);
157 }
158 }
159
160 inline void solve(){
161 ll now=0;
162 Matrix ans;
163 val[1]=1; int level;
164
165 for (int i=1;i<=all;){
166 for (int j=1;j<=80;++j)
167 for (int k=1;k<=m;++k) mp[j][k]=1;
168 for (int j=1;j<=large;++j) ans.a[j][1]=val[j];
169 ans=(e^(max(p[i].x-now-2,0ll)))*ans;
170 now=max(p[i].x-2,0ll);
171 for (int j=1;j<=large;++j) val[j]=ans.a[j][1];
172 int j=i+1;
173 mp[p[i].x-now][p[i].y]=p[i].type;
174 for (;j<=all;++j)
175 if(p[j].x>p[j-1].x+2) break;
176 else mp[p[j].x-now][p[j].y]=p[j].type;
177 level=p[j-1].x-now;
178 Get_ans(level);
179 i=j,now=p[j-1].x;
180 memset(val,0,sizeof(val));
181
182 for (int j=1;j<=tot[t];++j)
183 val[id[stk[t][j]]]=dp[t][j];
184
185 }
186 printf("%lld\n",val[1]);
187 }
188
189 signed main(){
190 for (int i=0;i<=10;++i) bit[i]=i<<1;
191 n=read(),m=read(),c=read(),d=read();
192 ll x,y;
193 for (int i=1;i<=c;++i) {
194 scanf("%lld%lld",&x,&y);
195 if(y==0) {
196 --i,--c;continue;
197 }
198 p[i]=(node){x,y,0};
199 }
200 for (int i=1;i<=d;++i) {
201 scanf("%lld%lld",&x,&y);
202 if(y==0) {
203 --i,--d;continue;
204 }
205 p[i+c]=(node){x,y,2};
206 }
207 sort(p+1,p+c+d+1);all=c+d;
208 if(p[c+d].x!=n) p[++all]=(node){n,m,1};
209 for (int i=1;i<=3;++i)
210 for (int j=1;j<=m;++j)
211 mp[i][j]=true;
212 DP(0,1,2);
213 for (int i=1;i<=tot[t];++i)
214 id[stk[t][i]]=i;
215 map<int,int>::iterator it;
216 large=id.size();
217 int i;
218 for (it=id.begin(),i=1;it!=id.end();++it){
219 rid[i]=it->first;
220 it->second=i++;
221 }
222 for (it=id.begin();it!=id.end();++it){
223 DP(it->first,1,1);
224 for (int i=1;i<=tot[t];++i) {
225 e.a[id[stk[t][i]]][it->second]=dp[t][i];
226 }
227 }
228 solve();
229 }
来源:https://www.cnblogs.com/Troywar/p/8391006.html
