Zhongshan Jizhong training Day5 Cheese is a test (designated Miao)

A group T1 matrix game (game) nine school entrance exam 24OI__D1T1

Problem Description

LZK invention is a matrix game, play it all together, there is a matrix of N rows and M columns. The first line is the number 1,2, ... M, is the number of the second row M + 1, M + 2 ... 2 * M, and so on, the number of N rows (N-1) * M + 1 , (N-1) * M + 2 ... N * M.
For example, N = 3, M = 4, the matrix is such that:
. 1. 3 2 4
. 5. 6. 7. 8
. 9. 11 10 12 is

As for the wisdom of God LZK, this matrix is ​​too boring, so he decided to transform this matrix, the transformation will be K times, each time a line will transform matrix or a column multiplied by a number, your task is to calculating a final number and all of this, the output of the matrix 109 answers + 7 mod.

Entry

The first line contains three positive integers N, M, K, represents the number of times the size of the transformation matrix. The next line, each line will be one of two forms:
RXY, it shows a first matrix X (1 ≤ X ≤ N) into the original line of the Y ( 0  ≤ the Y ≤ 10 ^ . 9 ) times.
SXY, It represents the first X (1 ≤ X ≤ M) into the original matrix row the Y ( 0 0 ≦ the Y ≤ 10 ^ . 9 ) times.

Export

A line output integer, the final matrix represents all of the elements and 10 . 9 + 7 result modulo 109 + 7.

Sample input and output

Sample 1

input
3 4 4
R 2 4
S 4 1
R 3 2
R 2 0
output
94

Sample 2

input
2 4 4
S 2 0
S 2 3
R 1 5
S 1 3
output
80

A sample explanation: after finishing this matrix becomes:
. 1. 4. 3 2
0 0 0 0
18 is 20 is 22 is 24

data range

40% of the data satisfies: 1 ≦ N, M≤1000;
80% of the data satisfies: 1≤N, M≤1000000,1 ≤ K ≤1000;
100% data satisfies: 1≤N, M≤1000000,1 ≤ K ≤100000.

Pretending to be cool analysis

  Dark observed shows

   1. The operations may be performed in any order, not affect the final result.

   2. Each row is an arithmetic sequence, and the beginning of tolerance is 1.

   3. Each column is a column obtained by adding the number of arithmetic sequence with a tolerance of all the tolerances and number of arithmetic sequence.

   We can consider advanced trekking operations, before proceeding column. After each line number multiplied by a number is still arithmetic sequence, tolerance corresponding increase in multiples. Thus, for each line, we only use the first term and maintain its tolerance enough. When the operation of the line get that done, the first column of the arithmetic sum of all numbers, and to give the first column, and then adding the tolerances, and tolerance to give each column, each column can be determined and the remaining It is directly on the column and multiply enough. ( Finally cut off handsomely excitement of a question )

 

#include<cstdio>
const int mod=1000000007;
int n,m,k,cnt;char ch[5];
int a[1000005],b[1000005],sum[1000005],d,ans;
struct node{int x,y;}q[100005];
int main()
{
    //freopen("game.in","r",stdin);freopen("game.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++)a[i]=(1ll*(i-1)*m+1)%mod,b[i]=1;
    for(int i=1,x,y;i<=k;i++)
    {
        scanf("%s%d%d",ch+1,&x,&y);
        if(ch[1]=='S'){q[++cnt].x=x,q[cnt].y=y;continue;}
        a[x]=(1ll*a[x]*y)%mod;b[x]=(1ll*b[x]*y)%mod;
    }
    for(int i=1;i<=n;i++)sum[1]=(sum[1]+a[i])%mod,d=(d+b[i])%mod;
    for(int i=2;i<=m;i++)sum[i]=(sum[i-1]+d)%mod;
    for(int i=1;i<=cnt;i++)sum[q[i].x]=(1ll*sum[q[i].x]*q[i].y)%mod;
    for(int i=1;i<=m;i++)ans=(ans+sum[i])%mod;
    printf("%d\n",ans);
}

 

 

 

A组T2 跳房子(jump)跳楼  

 ↑

导致我几天更不了博客的万恶之源

题目描述

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

输入格式

第一行包含两个正整数N,M,表示棋盘的大小。
接下来N行,每行M个整数,依次表示每个格子中的数字a[i,j]。
接下来一行包含一个正整数Q,表示操作次数。
接下来m行,每行一个操作。

输出格式

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

样例

样例输入

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⩽50,Q⩽5,000,k⩽50;
20的数据满足:3⩽N,M⩽200,Q⩽5,000,k⩽5,000;
另有20的数据满足:3⩽N,M⩽200,Q⩽5,000,k⩽10^9;
100的数据满足:3⩽N,M⩽2,000,Q⩽5,000,e,k⩽10^9;

看完题解才知道如何分析

  首先,图中肯定有环。但如果选择维护所有点是否在环上,一次更改操作复杂度就爆炸了。(于是考场上我选择一步一步走)其实只需要选一个折中的办法,维护第一列的每个点走n步回到第一列会到达哪个位置,以及第一列每个点是否在环上和环的长度即可(这是个基环树,只会有一个环)。

   对于每次移动操作,先暴力移动到第一列,再一行一行的跳,若跳到环则直接让 步数 模 环的长度,最后仍然一次跳一行,步数不足一行就暴力跳。

   对于每次修改操作,先判断修改的点的前面三个点中,哪些是会因为它的改变而改变路径,在倒退看第一列哪些点会经过这三个点,修改要维护的信息。

   修改时每个点都倒退回去显然是会TLE的,但我们发现两个相邻的点路径无法交叉,就像这样:

 

       显然这样的情况是不合法的。既然路径无法交叉,我们就只用维护受影响的点中两边上的几个点,就可以得到受影响的点的左右边界。(因为移动可能会越过边界,所以左边界可能比右边界还要大,这时维护矩阵两侧的点就好了)。讲得比我详细不知多少倍的原博客:https://www.cnblogs.com/wzc521/p/11310817.html

    代码(这道题写的我想去跳楼了,所以不要在意那个O2)

#pragma GCC optimize(2)
#include<cstdio>
int n,m,q,len,dx[]={-1,0,1};char ch[10];
int cir[4050],vis[4050],sta[4050],inst[4050],jump[4050],mart[4050][4050];
struct node{int x,y;}ans,p[50];
inline node nex(node o)
{
    int maxx=0,nex,y=o.y%m+1;
    for(int k=0,x;k<3;k++)if(mart[x=(o.x+dx[k]-1+n)%n+1][y]>maxx)maxx=mart[nex=x][y];
    return (node){nex,y};
}
inline node walk(node o,int k){if(!k)return o;return walk(nex(o),k-1);}
inline void judge(int x)
{
    vis[x]=inst[x]=1;sta[++sta[0]]=x;
    if(inst[jump[x]])
    {
        int y;len=0;
        do{inst[y=sta[sta[0]--]]=0;cir[y]=1;len+=m;}while(y!=jump[x]);
    }
    else if(!vis[jump[x]])judge(jump[x]);
    inst[x]=0;
}
inline void move(int k)
{
    while(k&&ans.y!=1)k--,ans=nex(ans);
    while(k>=m&&!cir[ans.x])k-=m,ans.x=jump[ans.x];
    k%=len;while(k>=m)k-=m,ans.x=jump[ans.x];
    while(k--)ans=nex(ans);
}
inline int fix(int x,int y,int k1)
{
    if(y==1)return x;int befx=-1;
    node bef;bef.y=(y-1-1+m)%m+1;
    for(int k=0;k<=2&&befx==-1;k++)
    bef.x=(x+k1*dx[k]-1+n)%n+1,befx=nex(bef).x==x&&nex(bef).y==y?fix(bef.x,bef.y,k1):-1;
    return befx;
}
inline void change(int a,int b,int e)
{
    int v[5][5]={0},y=(b-1-1+m)%m+1;
    for(int k=0;k<3;k++)p[k].x=(a-dx[k]-1+n)%n+1,p[k].y=y,v[k][0]=(nex(p[k]).x==a&&nex(p[k]).y==b);
    mart[a][b]=e;for(int k=0;k<3;k++)v[k][1]=(nex(p[k]).x==a&&nex(p[k]).y==b);
    for(int k=0,tot;k<3;k++)if(v[k][0]!=v[k][1])
    {
        tot=walk(p[k],m-p[k].y+1).x;
        int l=fix(p[k].x,p[k].y,1),r=fix(p[k].x,p[k].y,-1);
        if(l==-1||r==-1)continue;
        for(int i=l;i!=r;i=i%n+1)jump[i]=tot;jump[r]=tot;
    }
}
int main()
{
    //freopen("jump.in","r",stdin);freopen("jump.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&mart[i][j]);
    for(int i=1;i<=n;i++)jump[i]=walk((node){i,1},m).x;
    for(int i=1;i<=n;i++)if(!vis[i])judge(i);
    scanf("%d",&q);ans.x=ans.y=1;
    while(q--)
    {
        scanf("%s",ch);
        if(ch[0]=='m')
        {
            int k;scanf("%d",&k);
            move(k);
            printf("%d %d\n",ans.x,ans.y);
        }
        else
        {
            int a,b,e;scanf("%d%d%d",&a,&b,&e);
            change(a,b,e);
            for(int i=1;i<=n;i++)vis[i]=cir[i]=0;
            sta[0]=0;
            for(int i=1;i<=n;i++)if(!vis[i])judge(i);
        }
    }
}

 A组T3 优美序列(sequence)

问题描述

Lxy养了N头奶牛,他把N头奶牛用1..N编号,第i头奶牛编号为i。为了让奶牛多产奶,每天早上他都会让奶牛们排成一排做早操。奶牛们是随机排列的。在奶牛排列中,如果一段区间[L,R]中的数从小到大排列后是连续的,他认为这段区间是优美的。比如奶牛排列为:(3, 1, 7, 5, 6, 4, 2),区间[3,6]是优美的,它包含4,5,6,7连续的四个数,而区间[1,3] 是不优美的。Lxy的问题是:对于给定的一个区间[L,R](1<=L<=R<=N), 他想知道,包含区间[L,R]的最短优美区间,比如区间[1,3]的最短优美区间是[1,7]。

输入

第一行为一个整数N,表示奶牛的个数。
第二行为1到N的一个排列,表示奶牛的队伍。
第三行为一个整数M,表示有M个询问。
后面有M行,每行有两个整数L,R表示询问区间。

输出

输出为M行,每行两个整数,表示包含询问区间的最短优美区间。

输入输出样例

样例1

input
7
3 1 7 5 6 4 2
3
3 6
7 7
1 3
output
3 6
7 7
1 7

样例2

input
10
2 1 4 3 5 6 7 10 8 9
5
2 3
3 7
4 7
4 8
7 8
output
1 4
3 7
3 7
3 10
7 10

数据范围

15%的数据满足: 1 <=N,M <= 15;
50%的数据满足:1 <=N,M <= 1000。
100%的数据满足:1 <=N,M <= 100000。

根本不是正解的分析

  在一个大佬的博客看到了80分的算法:(原博客:https://www.cnblogs.com/Ch-someone/p/9664616.html

  “ 

     解析

 

       为了给出题人留面子,不让他被骂出个题只有一种解法而且只有满分解法,我先给个80分做法。
      预处理一个数组pos[i],表示数i在原数组的位置(第几个数)。
      在询问区间内找一个最小值和最大值,作为新的l和r,新的l和r作为一个询问区间,在pos数组里找一个最小值和最大值,他们再作为新的l和r,形成询问区间,在原数组寻找最小值和最大          值,并再次重复刚才的操作……
      上述过程可能很无脑很中二,然而这就是模拟题意找出答案的过程。
      最大值最小值用st表预处理,一共四个st表,比线段树好写……
      那么…… 
      正解是分治,像归并排序那样。
      不断求[l,mid] [mid+1,r]的优美序列,直到分成[mid,mid+1]
      可以证明是正确的。
      事实上分治做的熟练的人可能一眼秒这道题。

   ”

  于是,某个同学把这个80分解法拿过来加了个优化,然后就过了。。。。。

  优化是这样的:对于任意一个区间(l,r),它的最短优美区间一定包含它子区间的最短优美区间,所以用一个st表预处理以i为左端点,长度为2^j的区间的最短优美区间即可。

  代码:

#include<cstdio>
#include<algorithm>
const int maxn=2e5+5;
using namespace std;
struct node{int x,y;node(int x=131072,int y=0):x(x),y(y){}}ans,pre[maxn][18];
int n,m,a[maxn],log[maxn],pos[maxn];
int mx[maxn][18],mn[maxn][18],mxp[maxn][18],mnp[maxn][18];
inline void print(int x){if(x>9)print(x/10);putchar(x%10+48);}
inline int read(){register int x=0;char ch;while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x;}
inline node solve(int l,int r)
{
    int minn,maxx,k,k1;k=log[r-l+1];
    while((maxx=max(mx[l][k],mx[r-(1<<k)+1][k]))-(minn=min(mn[l][k],mn[r-(1<<k)+1][k]))!=r-l)
    k1=log[maxx-minn+1],l=min(mnp[minn][k1],mnp[maxx-(1<<k1)+1][k1]),
    r=max(mxp[minn][k1],mxp[maxx-(1<<k1)+1][k1]),k=log[r-l+1];
    return node(l,r);
}
void prework()
{
    for(int i=1;i<=n;i++)pre[i][0]=node(i,i);
    for(register int i=1;i<=log[n];i++)for(register int j=1;j<=n&&j+(1<<(i-1))<=n;j++)
    pre[j][i]=solve(min(pre[j][i-1].x,pre[j+(1<<(i-1))][i-1].x),max(pre[j][i-1].y,pre[j+(1<<(i-1))][i-1].y));
}
int main()
{
    //freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);
    scanf("%d",&n);
    for(register int i=1;i<=n;i++)a[i]=read(),mxp[a[i]][0]=mnp[a[i]][0]=pos[mn[i][0]=mx[i][0]=a[i]]=i,log[i+1]=log[(i+1)/2]+1;;
    for(register int i=1;i<=log[n];i++)for(register int j=1;j<=n&&j+(1<<(i-1))<=n;j++)
    mn[j][i]=min(mn[j][i-1],mn[j+(1<<(i-1))][i-1]),mx[j][i]=max(mx[j][i-1],mx[j+(1<<(i-1))][i-1]),
    mnp[j][i]=min(mnp[j][i-1],mnp[j+(1<<(i-1))][i-1]),mxp[j][i]=max(mxp[j][i-1],mxp[j+(1<<(i-1))][i-1]);
    prework();
    scanf("%d",&m);
    for(register int i=1,l,r,k;i<=m;i++)
    {
        l=read(),r=read(),k=log[r-l+1];
        ans=solve(min(pre[l][k].x,pre[r-(1<<k)+1][k].x),max(pre[r-(1<<k)+1][k].y,pre[l][k].y));
        print(ans.x);putchar(' ');print(ans.y);puts("");
    }
}

 

Guess you like

Origin www.cnblogs.com/firecrazy/p/11332810.html