zoukankan      html  css  js  c++  java
  • CSYZDay1模拟题解

    T1.game

    【问题描述】

    LZK发明一个矩阵游戏,大家一起来玩玩吧,有一个NM列的矩阵。第一行的数字是1,2,M,第二行的数字是M+1,M+22*M,以此类推,第N行的数字是(N-1)*M+1,(N-1)*M+2N*M

    例如,N=3,M=4的矩阵是这样的:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    对于身为智慧之神的LZK来说,这个矩阵过于无趣.于是他决定改造这个矩阵,改造会进行K,每次改造会将矩阵的某一行或某一列乘上一个数字,你的任务是计算最终这个矩阵内所有数字的和,输出答案对109+7取模。

    【输入】

    第一行包含三个正整数NMK,表示矩阵的大小与改造次数。接下来的行,每行会是如下两种形式之一:

    R X Y,表示将矩阵的第X(1 X N)行变为原来的Y(0 Y 109).

    S X Y,表示将矩阵的第X(1 X M)列变为原来的Y(0 Y ).

    输出】

    输出一行一个整数,表示最终矩阵内所有元素的和对109+7取模的结果。

     

    【数据范围】

     

    40%的数据满足:1N,M1000

     

    80%的数据满足:1N,M1000000,1 K 1000

    100%的数据满足:1N,M1000000,1 K 100000。、

     

    个人觉得T1还是比较简单的,因为这个矩阵最后的和与乘法操作的先后顺序没有关系,所以我们可以先把所有行的操作乘完,记录每行被乘的数取模之后的结果。之后选择把第一列的所有数加起来,后面每列与之相差的值就是每行被乘的倍数之和。这样的话线性相加之后每次再乘以这一列被乘的情况就可以啦。

    看一下代码。千万要注意在linux下有字符读入的不要使用单个的getchar,否则在读取的时候会出错,可以选择使用cin,scanf或者多个getchar进行读入。

    (这题在Linux下评测的话我原来代码会爆零,但是windows下是可以过的)

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<set>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int N = 1000005;
    const ll mod = 1e9+7;
    
    ll read()
    {
        ll ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    struct ask
    {
        ll pos,val; 
    }r[M],s[M];
    ll n,m,k,tot1,tot2,cur,ans,sum;
    ll po[N],ro[N];
    
    int main()
    {
      //freopen("game.in","r",stdin);
      //freopen("game.out","w",stdout);    
        n = read(),m = read(),k = read();
        rep(i,1,k)
        {
          char c;
          cin >> c;
          if(c == 'R') r[++tot1].pos = read(),r[tot1].val = read();
          else if(c == 'S')s[++tot2].pos = read(),s[tot2].val = read();
        }
        rep(i,1,n) po[i] = 1;rep(i,1,m) ro[i] = 1;
        rep(i,1,tot1) po[r[i].pos] *= r[i].val,po[r[i].pos] %= mod;
        rep(i,1,n) 
        {
            ll p = 1 + (i-1) * m; p %= mod;
            cur += p * po[i],cur %= mod;
            sum += po[i];
            if(sum >= mod) sum -= mod;
        }
        rep(i,1,tot2) ro[s[i].pos] *= s[i].val,ro[s[i].pos] %= mod;
        rep(i,1,m) 
        {
            ans += cur * ro[i],ans %= mod;
            cur += sum;
            if(cur >= mod) cur -= mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }

    T2.jump

    【问题描述】

    跳房子,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。

    跳房子是在N个格子上进行的,CYJ对游戏进行了改进,该成了跳棋盘,改进后的游戏是在一个NM列的棋盘上进行,并规定从第一行往上可以走到最后一行,第一列往左可以走到最后一列,反之亦然每个格子上有一个数字。
    在这个棋盘左上角
    (1,1)放置着一枚棋子。每次棋子会走到右、右上和右下三个方向格子中对应上数字最大一个。任意时刻棋子都只有一种走法,不存在多个格子同时满足条件。
    现在有两种操作:
    move k
    将棋子前进k步。
    change a b e
    将第a行第b列格子上的数字修改为e
    请对于每一个move操作输出棋子移动完毕后所处的位置。

    【输入】

    第一行包含两个正整数N,M(3<=N,M<=2000),表示棋盘大小
    接下来
    N行,每行M个整数,依次表示每个格子中的数字a[i,j](1<= a[i,j]<=109)
    接下来一行包含一个正整数
    Q(1<=Q<=5000),表示操作次数。
    接下来m行,每行一个操作,其中1<=a<=N,1<=b<=M,1<=k,e<=109

    输出】

    对于每个move操作,输出一行两个正整数x,y,即棋子所处的行号和列号。

    【输入输出样例】

    jump.in

    jump.out

    4 4

    1 2 9 3

    3 5 4 8

    4 3 2 7

    5 8 1 6

    4

    move 1

    move 1

    change 1 4 100

    move 1

    4 2

    1 3

    1 4


    【数据范围】

    10%的数据满足:3<= N,M <=50Q<=5000k<=10

    20%的数据满足:3<= N,M <=200Q<=5000k<=5000

    另有20%的数据满足:3<= N,M <=200Q<=5000k<=109

    100%的数据满足:3<= N,M <=2000Q<=5000e,k<=109

    这题当时想到了暴力的40分不过由于没有时间给写跪了。因为n×m内必出循环节(踩到一个走过的格子即进入循环节)

    至于100分做法怎么做呢?正解的做法我看不大懂……所以使用了学姐的线段树维护置换的方法。我们记录对于每一列,在每一行其向下一列会走到哪。这样的话每一列都建立了一个置换,之后我们只要把他们全部乘起来就行。在行走的时候,如果步数够得话就直接用置换跳着走(每次走m列),否则一步一步走就可以。

    至于修改操作,我们只需要修改这个点的左边,左上,左下三个点,之后直接在线段树内重新维护置换即可。

    或许很难懂……看一下子恒dalao的代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<queue>
    #include<set>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 50005;
    const int N = 2005;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    int n,m,f[N][N];
    char s[15];
    
    struct node
    {
        int g[N];
        node()
        {
        rep(i,1,n) g[i] = i;
        }
        node operator * (const node &b)const
        {
        node c;
        rep(i,1,n) c.g[i] = b.g[g[i]];
        return c;
        }
    }nxt[N],t[N<<2];
    
    node qpow(node k,int b)
    {
        node res;
        while(b)
        {
        if(b & 1) res = res * k;
        k = k * k;
        b >>= 1;
        }
        return res;
    }
    
    int pos(int x,bool flag)//pos函数用于确定取模之后的实际位置
    {
        if(x == (flag ? m+1 : n+1)) return 1;
        if(!x) return flag ? m : n;
        return x;
    }
    
    void change(int x,int y)
    {
        int maxn = 0;
        x = pos(x,0),y = pos(y,1);
        rep(k,-1,1)
        {
        int kx = pos(k+x,0),ky = pos(y+1,1);
        if(maxn < f[kx][ky]) maxn = f[kx][ky],nxt[y].g[x] = kx;
        }
    }
    
    void build(int p,int l,int r)
    {
        if(l == r)
        {
        t[p] = nxt[l];
        return;
        }
        int mid = (l+r) >> 1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        t[p] = t[p<<1] * t[p<<1|1];
    }
    
    void modify(int p,int l,int r,int v)
    {
        if(l == r)
        {
        t[p] = nxt[v];
        return;
        }
        int mid = (l+r) >> 1;
        if(v <= mid) modify(p<<1,l,mid,v);
        else modify(p<<1|1,mid+1,r,v);
        t[p] = t[p<<1] * t[p<<1|1];
    }
    void move(int &x,int &y,int k)
    {
        while(k--) x = nxt[y].g[x],y = pos(y+1,1);
    }
    
    int main()
    {
        n = read(),m = read();
        rep(i,1,n)
        rep(j,1,m) f[i][j] = read();
        rep(i,1,n)
        rep(j,1,m) change(i,j);
        build(1,1,m);
        int q = read(),px = 1,py = 1;
        while(q--)
        {
        scanf("%s",s);
        if(s[0] == 'm')
        {
            int k = read(),len = min(k,m - py + 1);
            move(px,py,len),k -= len;
            if(k) px = qpow(t[1],k/m).g[px],k %= m,move(px,py,k);
            printf("%d %d
    ",px,py);
        }
        else
        {
            int a = read(),b = read(),c = read();
            f[a][b] = c;
            change(a-1,b-1),change(a,b-1),change(a+1,b-1);
            modify(1,1,m,pos(b-1,1));
        }
        }
        return 0;
    }

    T3.sequence

    这题确实不会做了……考试的时候线段树无限暴力52pts。

    正解也看不大懂……直接放出暴力代码吧。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<set>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int INF = 1e9+7;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    struct seg
    {
        int v,minx,maxx;
    }t[M<<2];
    
    int n,m,a[M],al,ar,pos[1005][1005],tot[M];
    
    void build(int p,int l,int r)
    {
        if(l == r) 
        {
            t[p].minx = t[p].maxx = a[l];
            return;
        }
        int mid = (l+r) >> 1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        t[p].minx = min(t[p<<1].minx,t[p<<1|1].minx);
        t[p].maxx = max(t[p<<1].maxx,t[p<<1|1].maxx);
    }
    
    int query(int p,int l,int r,int kl,int kr,bool flag)
    {
        if(l == kl && r == kr) return flag? t[p].minx : t[p].maxx;
        int mid = (l+r) >> 1;
        if(kr <= mid) return query(p<<1,l,mid,kl,kr,flag);
        else if(kl > mid) return query(p<<1|1,mid+1,r,kl,kr,flag);
        else 
        {
            if(flag) return min(query(p<<1,l,mid,kl,mid,flag),query(p<<1|1,mid+1,r,mid+1,kr,flag));
            else return max(query(p<<1,l,mid,kl,mid,flag),query(p<<1|1,mid+1,r,mid+1,kr,flag));
        }
    }
    
    void init()
    {
        rep(i,1,n)
        {
            rep(j,i+1,n)
            {
                int k1 = query(1,1,n,i,j,1),k2 = query(1,1,n,i,j,0);
                if(k2-k1+1 == j-i+1) pos[i][++tot[i]] = j;
            }
        }
    }
    
    void solve(int l,int r)
    {
        int cur = INF,pos1,pos2;
        per(i,l,1) 
        {
            int k = lower_bound(pos[i]+1,pos[i]+1+tot[i],r) - pos[i];
            if(k == tot[i]+1) continue;
            if(pos[i][k]-i+1 < cur) cur = pos[i][k]-l+1,pos1 = i,pos2 = pos[i][k];
        }
        printf("%d %d
    ",pos1,pos2);
    }
    int main()
    {
        freopen("sequence.in","r",stdin);
        freopen("sequence.out","w",stdout);    
        n = read(); rep(i,1,n) a[i] = read();
        build(1,1,n);
        init();
        m = read();
        rep(i,1,m)
        {
            al = read(),ar = read();
            solve(al,ar);
        }
        return 0;
    }

    这么长时间过去还是没有理解这题咋做……太弱了orz。

    算是把坑填一下。

  • 相关阅读:
    Linux命令之_Cut(转)
    Use “error_messages” in Rails 3.2? (raises “undefined method” error)
    ruby错误
    Linux SvN操作
    Linux 安装SVN服务器 (转)
    删除 vim 命令
    vscode 配置java开发
    java json
    svn
    采样率和比特率
  • 原文地址:https://www.cnblogs.com/captain1/p/9664281.html
Copyright © 2011-2022 走看看