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 Core Dump
    ODP.NET Managed正式推出
    获取EditText的光标位置
    (Java实现) 洛谷 P1603 斯诺登的密码
    (Java实现) 洛谷 P1603 斯诺登的密码
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1028 数的计算
  • 原文地址:https://www.cnblogs.com/captain1/p/9664281.html
Copyright © 2011-2022 走看看