T1[A. 矩阵游戏]
40%算法
首先注意几个性质:先乘后乘,或有没有0都一样,
记录下每一行,每一列乘的累计值$a_i b_j$
最后$ans=cal(i,j)*a_i*b_j$ 其中cal为O(1)计算初始每个位置的值$O(nm)$枚举
100%算法
只需要把式子展开,然后就能分别O(n)O(m)计算
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #define R register 6 #define int long long 7 using namespace std; 8 int read() 9 { 10 int f=1,x=0;char ch=getchar(); 11 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 13 return f*x; 14 } 15 const int maxn=1000005; 16 const int mod=1e9+7; 17 int n,m,k; 18 int a[maxn],b[maxn]; 19 int fa[maxn],fb[maxn]; 20 char opt[3]; 21 int cal(int x,int y) 22 { 23 return ((x-1)*m%mod+y)%mod; 24 } 25 signed main() 26 { 27 // freopen("data","r",stdin); 28 n=read(),m=read(),k=read(); 29 for(int i=1;i<=n;i++) 30 fa[i]=1; 31 for(int i=1;i<=m;i++) 32 fb[i]=1; 33 while(k--) 34 { 35 scanf("%s",opt); 36 R int x=read(),y=read(); 37 if(opt[0]=='R') 38 { 39 fa[x]=fa[x]*y%mod; 40 } 41 else 42 { 43 fb[x]=fb[x]*y%mod; 44 } 45 } 46 int sum=0,dtb=0,ta=0; 47 for(int i=1;i<=n;i++){ 48 ta=(ta+(i-1)*m%mod*fa[i]%mod)%mod; 49 dtb=(dtb+fa[i])%mod; 50 } 51 for(int j=1;j<=m;j++) 52 (sum+=fb[j]*ta%mod+j*fb[j]%mod*dtb%mod)%=mod;; 53 printf("%lld\n",sum%mod); 54 }
T2[B. 跳房子]「模拟」
20%算法
傻模拟,别预处理,否则改的挺麻烦的,
80%算法
记录一下每一列的上一次经过时的横坐标,当与这一次访问的横坐标相等时,证明这构成了一个以m为一个循环长度的循环解,
将k取模,省得暴力走完,就能求出答案,修改时暴力修改
100%算法
记录第一列的每个点走m步之后到了第一列的某点jump[i]
然后不断跳,直到找到一个走过的点,然后记录一下这其中的走的步数,用k减去
修改:除了修改每个点本身的值,还要修改这个点所影响的第一列的一个范围,
容易发现,这会形成一个区间,只要找到这个区间的上下边界,
y--的同时,分别看上下边界能否扩展,若其一不能扩展或缩小至下边界高于上边界,return就行,不会对jump有影响
那么有没有可能这个return的这个边界的另一条可行道路接着走不会return呢?
显然是不可能的,,手模一下,,一个边界无法扩展的条件只有上下两个边界紧挨着时
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<string> 6 #define R register 7 #define INF 0x7fffffff 8 using namespace std; 9 inline int read(){ 10 R int f=1,x=0;char ch=getchar(); 11 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 13 return f*x; 14 } 15 int n,m,a[2100][2100],v[2100],jump[2005];// v[i] whether irow has been arrived 16 int vk[2100];//when is irow arrived 17 int fx(int x){return ((x-1)%n+n)%n+1;} 18 int fy(int y){return ((y-1)%m+m)%m+1;} 19 inline int mov(int x,int y)//go ahead 20 { 21 R int nxt=-1,mx=-1; 22 for(R int i=x-1;i<=x+1;++i){ 23 R int da=a[fx(i)][fy(y+1)]; 24 if(da>mx){ 25 mx=da; 26 nxt=i; 27 } 28 } 29 return nxt; 30 } 31 inline int mof(int x,int y)//from (x,y) to (x',1) 32 { 33 do{ 34 x=fx(mov(x,y)); 35 y++; 36 }while(y<=m); 37 return x; 38 } 39 inline void update(int x,int y) 40 { 41 const int tx=mof(x,y); 42 int low=x,high=x,yy=y; 43 while(yy!=1) 44 { 45 --yy; 46 int lo=INF,hi=-INF; 47 for(int i=low-1;i<=low+1;i++){ 48 int nxx=mov(i,yy); 49 if(nxx<=high&&nxx>=low){ 50 lo=i; 51 break; 52 } 53 } 54 for(int i=high+1;i>=high-1;i--){ 55 int nxx=mov(i,yy); 56 if(nxx<=high&&nxx>=low){ 57 hi=i; 58 break; 59 } 60 } 61 if(lo>hi)return; 62 low=lo,high=hi; 63 } 64 if(high-low+1>=n) 65 for(int i=1;i<=n;i++) 66 jump[i]=tx; 67 else 68 for(int i=low;i<=high;++i) 69 jump[fx(i)]=tx; 70 } 71 inline void move(R int &x,R int &y,R int k) 72 { 73 memset(v,0,sizeof v); 74 memset(vk,0,sizeof vk); 75 if(k>=(m-y+1)){// can arrive 1 column 76 k-=(m-y+1); 77 x=mof(x,y); 78 y=1; 79 } 80 v[x]=1,vk[x]=k; 81 while(k>=m){ 82 k-=m; 83 x=jump[x]; 84 if(v[x]) 85 { 86 int len=vk[x]-k; 87 if(k>=len){ 88 int nu=k/len; 89 k-=nu*len; 90 } 91 } 92 v[x]=1,vk[x]=k; 93 } 94 while(k--) x=fx(mov(x,y++)); 95 } 96 int main() 97 { 98 n=read(),m=read(); 99 for(R int i=1;i<=n;++i) 100 for(int j=1;j<=m;++j) 101 a[i][j]=read(); 102 for(int i=1;i<=n;i++) 103 jump[i]=mof(i,1); 104 const int Q=read(); 105 R int x=1,y=1; 106 for(R int q=1;q<=Q;++q) 107 { 108 R char opt[16]; 109 scanf("%s",opt); 110 if(opt[0]=='m') 111 { 112 int k=read(); 113 move(x,y,k); 114 printf("%d %d\n",x,y); 115 } 116 else 117 { 118 R int xx=read(),yy=read(),w=read(); 119 a[xx][yy]=w; 120 for(int i=xx-1;i<=xx+1;i++) 121 update(fx(i),fy(yy-1)); 122 } 123 } 124 return 0; 125 }
T3[C. 优美序列]「ST表」「莫队」
60%算法
性质对于给定的区间[x,y],找出最大值和最小值,比较mx-mi是否等于y-x
若不等则说明还有[mi,mx]内的点没有包含,那么再扩展x,y
扩展方式是:记录每个值的所在位置pos[i],找到[mi,mx]内的极值对应y,x
然后不断反复扩展,直到$mx-mi==y-x$
80%算法
用ST表维护两个数组的两个极值
100%算法
毒瘤卡常+莫队优化
将询问按照尽量从里向外的方式排序,1.若上一个区间的ans范围大于该区间的原始长度,直接赋值,2.并且把该区间长度缩小至上一个,以供下一个区间使用
3.若这个区间虽然不满足上一个要求,但它的最值和上一个相同,也直接赋值
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define R register 7 using namespace std; 8 inline int read() 9 { 10 R int x=0;char ch=getchar(); 11 while(ch>'9'||ch<'0')ch=getchar(); 12 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 13 return x; 14 } 15 const int maxn=100005; 16 struct node{ 17 int l,r,id,mx,mi; 18 }q[maxn]; 19 int n,a[maxn],pos[maxn],lg[maxn],al[maxn],ar[maxn]; 20 int ax[17][maxn],ai[17][maxn]; 21 int bx[17][maxn],bi[17][maxn]; 22 inline bool cmp(node a,node b){return (a.l==b.l)?a.r<b.r:a.l>b.l;} 23 inline void ST_pre() 24 { 25 for(R int i=1;i<=n;++i){ 26 ax[0][i]=ai[0][i]=a[i], 27 bx[0][i]=bi[0][i]=pos[i]; 28 if(i!=1)lg[i]=lg[i>>1]+1; 29 } 30 const int t=lg[n]+1; 31 for(R int j=1;j<t;++j) 32 for(R int i=1;i<=n-(1<<j)+1;++i){ 33 ax[j][i]=max(ax[j-1][i],ax[j-1][i+(1<<(j-1))]); 34 ai[j][i]=min(ai[j-1][i],ai[j-1][i+(1<<(j-1))]); 35 bx[j][i]=max(bx[j-1][i],bx[j-1][i+(1<<(j-1))]); 36 bi[j][i]=min(bi[j-1][i],bi[j-1][i+(1<<(j-1))]); 37 } 38 } 39 inline int ask(R int l,R int r,R int pd) 40 { 41 const int t=lg[r-l+1]; 42 if(pd==1)return max(ax[t][l],ax[t][r-(1<<t)+1]); 43 if(pd==2)return min(ai[t][l],ai[t][r-(1<<t)+1]); 44 if(pd==3)return max(bx[t][l],bx[t][r-(1<<t)+1]); 45 if(pd==4)return min(bi[t][l],bi[t][r-(1<<t)+1]); 46 } 47 int main() 48 { 49 //freopen("sequence24.in","r",stdin); 50 n=read(); 51 for(R int i=1;i<=n;++i){ 52 a[i]=read(), 53 pos[a[i]]=i; 54 } 55 ST_pre(); 56 const int Q=read(); 57 for(R int i=1;i<=Q;++i){ 58 q[i].l=read(), 59 q[i].r=read(), 60 q[i].id=i; 61 } 62 sort(q+1,q+1+Q,cmp); 63 for(R int i=1;i<=Q;++i) 64 { 65 if(q[i].l<=q[i-1].l&&q[i].r>=q[i-1].r&&al[q[i-1].id]<=q[i].l&&ar[q[i-1].id]>=q[i].r){ 66 al[q[i].id]=al[q[i-1].id],ar[q[i].id]=ar[q[i-1].id]; 67 q[i].l=q[i-1].l,q[i].r=q[i-1].r; 68 continue; 69 } 70 R int x=q[i].l,y=q[i].r; 71 R int mx=ask(x,y,1),mi=ask(x,y,2); 72 q[i].mx=mx,q[i].mi=mi; 73 if(q[i].mx==q[i-1].mx&&q[i].mx==q[i].mi){ 74 al[q[i].id]=al[q[i-1].id],ar[q[i].id]=ar[q[i-1].id]; 75 continue; 76 } 77 while(1) 78 { 79 y=ask(mi,mx,3),x=ask(mi,mx,4); 80 if(y-x==mx-mi)break; 81 mx=ask(x,y,1),mi=ask(x,y,2); 82 } 83 al[q[i].id]=x,ar[q[i].id]=y; 84 85 } 86 for(R int i=1;i<=Q;++i) 87 printf("%d %d\n",al[i],ar[i]); 88 }