zoukankan      html  css  js  c++  java
  • noip模拟测试13


    T1:矩阵游戏

      刚看题一脸懵,感觉一点思路都没有……

      然后就开始看题目,发现题目描述里似乎藏着什么东西???

      感觉题目闲的无聊疯狂描述了一个极其简单的东西,好像在暗示着什么!

      所以就把题目中的式子写下来——$(i-1)*m+j$

      再用这个式子把答案表示出来——$sum_{i=1}^nR_isum_{j=1}^mS_j[(i-1)*m+j]$

      然后把含有$i$的项拆出来就可以$O(n)$做了

      

      so,code

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<vector>
     7 #define ll long long
     8 using namespace std;
     9 const int MAXN=1000005,MAXK=100005,D=1e9+7;
    10 int n,m,k;
    11 ll sums,sumr,s[MAXN],r[MAXN],ans,tmp,sum;
    12 char opt[5];
    13 int main() {
    14     scanf("%d%d%d",&n,&m,&k);
    15     for(int i=1;i<=m;i++) s[i]=1;
    16     for(int i=1;i<=n;i++) r[i]=1;
    17     for(int i=1;i<=k;i++) {
    18         ll x,y;
    19         scanf("%s%lld%lld",opt,&x,&y);
    20         if(opt[0]=='R') r[x]=r[x]*y%D;
    21         else s[x]=s[x]*y%D;
    22     }
    23     for(int i=1;i<=m;i++) sums=(sums+s[i])%D;
    24     for(int i=1;i<=m;i++) tmp=(tmp+s[i]*i)%D;
    25     for(int i=1;i<=n;i++) ans=(ans+(tmp+(ll)(i-1)*m%D*sums)%D*r[i]%D)%D;
    26     printf("%lld
    ",(ans%D+D)%D);
    27     return 0;
    28 }
    t1 Code


    T2:跳房子

       看到k的范围首先想到矩阵乘,但又看了看n和m还是算了

      发现更改操作最多只会影响前面的三个点,于是就连边暴力跑,

      又发现好像建出的图是n个点,n条边的有向图,那就必是内向的基环树森林

      很容易想到当k很大的时候就是一直在环上绕,所以可以对环的长度取一下模,复杂度就差不多是$n*mlogk$

      还是不太对,于是利用分块的思想(???)将每一行看作一个点

      因为每走$m$次后必定会再回到第一行,所以可以定义一个$jump$数组

      $jump[i]$表示从第$i$行第一列走m步后会到达第一列的哪一行

      然后会发现$jump$数组构成的图也是内向的基环树森林

      所以就可以利用分块的思想,小段暴力(move),大段分块(jump),再在jump的时候找循环节优化

      这样查询的复杂度就可以做到$O(n+m)$

      那修改呢?

      通过手玩数据(???)我们可以发现,对于一个修改,最多会影响它前面3个点的路径

      我们考虑其中的一个,对于一个路径改变的点,它的影响应该是这样的:

      

      它只会影响到它之前的一个连续区间(当然这个区间也可以跨过边界)

      为什么呢?因为当确定了某一列的一个连续区间一定会走到某点时

      上一列中位于区间中部的一些点必定会走到区间内,所以也必定会走到某点

      而位于区间两端的一些点则可能走向区间,也可能不走向区间

      而正是这些两端的点决定了该行区间的拓展或是收缩

      那么思路就很显然了我们只要在修改时维护一个区间

      每次向前一列时只需要用当前区间两端的点来更新区间就好了

      复杂度为$O(n+m)$

      

      细节比较多,具体还是看代码吧

      so,code  

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<vector>
      7 #define ll long long
      8 using namespace std;
      9 const int MAXN=4005,INF=0x7f7f7f7f;
     10 int n,m,q,s[MAXN][MAXN],jump[MAXN],lst[MAXN],vis[MAXN],tim;
     11 char opt[20];
     12 struct node {
     13     int x,y;
     14 }ver[MAXN][MAXN],now;
     15 void add(int x,int y) {
     16     int ny=y==m?1:y+1;
     17     int nx[3]={x==1?n:x-1,x,x==n?1:x+1};
     18     int mxs=max(s[nx[0]][ny],max(s[nx[1]][ny],s[nx[2]][ny]));
     19     if(mxs==s[nx[0]][ny])
     20         ver[x][y].x=nx[0],ver[x][y].y=ny;
     21     else if(mxs==s[nx[1]][ny])
     22         ver[x][y].x=nx[1],ver[x][y].y=ny;
     23     else ver[x][y].x=nx[2],ver[x][y].y=ny;
     24 }
     25 node move(node u,int k) {
     26     if(!k) return u;
     27     return move(ver[u.x][u.y],k-1);
     28 }
     29 void get_ver() {
     30     for(int i=1;i<=n;i++)
     31         for(int j=1;j<=m;j++)
     32             add(i,j);
     33 }
     34 void get_jump() {
     35     for(int i=1;i<=n;i++) {
     36         node tmp;
     37         tmp.x=i,tmp.y=1;
     38         tmp=move(tmp,m);
     39         jump[i]=tmp.x;
     40     }
     41 }
     42 bool cirflag;
     43 int jump_move(int x,int k,int t) {
     44     if(!cirflag&&vis[x]==tim) k%=(t-lst[x]),cirflag=1;
     45     if(!k) return x;
     46     if(!cirflag) lst[x]=t;
     47     vis[x]=tim;
     48     return jump_move(jump[x],k-1,t+1);
     49 }
     50 int legal(int p,int o) {
     51     if(!o) return ((p-1)%n+n)%n+1;
     52     else return ((p-1)%m+m)%m+1;
     53 }
     54 int visit(int x,int y) {
     55     int tmp=legal(x,0);
     56     int nx=ver[tmp][y].x,ret;
     57     if(tmp==1&&nx==n) ret=x-1;
     58     else if(tmp==n&&nx==1) ret=x+1;
     59     else ret=x+(nx-tmp);
     60     return ret;
     61 }
     62 void change(int x,int y) {
     63     x=legal(x,0);
     64     y=legal(y,1);
     65     node tmp;tmp.x=x,tmp.y=y;
     66     tmp=move(tmp,m-y+1);
     67     int mini=x,maxi=x,ny=y;
     68     while(ny>1) {
     69         --ny;
     70         int tmpmi=INF,tmpmx=-INF;
     71         for(int i=mini-1;i<=mini+1;i++) {
     72             int to=visit(i,ny);
     73             if(mini<=to&&to<=maxi) {
     74                 tmpmi=i;
     75                 break;
     76             }
     77         }
     78         for(int i=maxi+1;i>=maxi-1;i--) {
     79             int to=visit(i,ny);
     80             if(mini<=to&&to<=maxi) {
     81                 tmpmx=i;
     82                 break;
     83             }
     84         }
     85         if(tmpmi>tmpmx) return;
     86         mini=tmpmi,maxi=tmpmx;
     87     }
     88     if(maxi-mini+1>=n)
     89         for(int i=1;i<=n;i++) jump[i]=tmp.x;
     90     else for(int i=mini;i<=maxi;i++)
     91         jump[legal(i,0)]=tmp.x;
     92 }
     93 int main() {
     94     scanf("%d%d",&n,&m);
     95     for(int i=1;i<=n;i++)
     96         for(int j=1;j<=m;j++)
     97             scanf("%d",&s[i][j]);
     98     get_ver();
     99     get_jump();
    100     scanf("%d",&q);
    101     now.x=now.y=1;
    102     for(int i=1,aa,bb,cc;i<=q;i++) {
    103         scanf("%s",opt);
    104         if(opt[0]=='c') {
    105             scanf("%d%d%d",&aa,&bb,&cc);
    106             s[aa][bb]=cc;
    107             for(int i=aa-1;i<=aa+1;i++)
    108                 add(legal(i,0),legal(bb-1,1));
    109             for(int i=aa-1;i<=aa+1;i++)
    110                 change(i,bb-1);
    111         } else {
    112             scanf("%d",&cc);
    113             while(cc&&now.y!=1) now=ver[now.x][now.y],--cc;
    114             if(cc) {
    115                 ++tim;cirflag=0;
    116                 now.x=jump_move(now.x,cc/m,1),now.y=1;
    117                 now=move(now,cc%m);
    118             }
    119             printf("%d %d
    ",now.x,now.y);
    120         }
    121     }
    122     return 0;
    123 }
    t2 Code

      ps:如果发现调细节心态崩了的话,可以看看另一种思路——线段树维护置换 ---->oiertkj 



    T3:优美序列


  • 相关阅读:
    RE
    【LeetCode】198. House Robber
    【LeetCode】053. Maximum Subarray
    【LeetCode】152. Maximum Product Subarray
    【LeetCode】238.Product of Array Except Self
    【LeetCode】042 Trapping Rain Water
    【LeetCode】011 Container With Most Water
    【LeetCode】004. Median of Two Sorted Arrays
    【LeetCode】454 4Sum II
    【LeetCode】259 3Sum Smaller
  • 原文地址:https://www.cnblogs.com/Gkeng/p/11302156.html
Copyright © 2011-2022 走看看