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