模拟13 题解

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 }
View Code

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 }
View Code

 

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 }
View Code

 

转载于:https://www.cnblogs.com/casun547/p/11312067.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值