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('\n')

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\n",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('\n')

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\n",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('\n')

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\n",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。

算是把坑填一下。

 

posted @ 2018-10-04 21:03  CaptainLi  阅读(720)  评论(1编辑  收藏  举报