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:优美序列


  • 相关阅读:
    cocos2dx——九宫格CCScale9Sprite
    COCOS学习笔记--TexturePacker使用详解
    leetcode 旋转数组
    leetcode 从排序数组中删除重复项
    使用javascript随机生成斗地主玩家手牌
    模仿w3c school的示例导航栏
    c#中快速排序的学习
    常用语法梳理
    技巧类
    markdown备忘
  • 原文地址:https://www.cnblogs.com/Gkeng/p/11302156.html
Copyright © 2011-2022 走看看