1. 程式人生 > >2017年11月1日普及組模擬賽【解題報告】

2017年11月1日普及組模擬賽【解題報告】

第一題 I Got a Matrix!

大意

給定一個長和寬都小於等於100的矩陣,求出矩陣邊緣的和

思路

暴力模擬

程式碼

#include<cstdio>
using namespace std;
int a,n,m,i,j;
long long s;
int main()
{
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);
    i=1;j=0;scanf("%d%d",&n,&m);
    while (scanf("%d",&a)==1
) {j++;if (j>m){i++;j=1;}if (i==1||j==1||i==n||j==m) s+=a;}//直接判斷 printf("%lld",s);//輸出 return 0; }

第二題 I Liked Matrix!

大意

給定一個n×m 的矩陣A,對其進行q 次詢問:以(x1; y1) 為左上角,(x2; y2) 為右下角的子矩
陣中,所有元素的最大值。

思路

暴力模擬

程式碼

#include<cstdio>
#include<algorithm>
#define input read()
using namespace std; int a[101][101]; int x1,y1,x2,y2,maxx; int n,m,q; int read()//輸入流不解釋 { char c;int d=1;int f=0; while (c=getchar(),c<'0'||c>'9') if(c=='-')d=-1;f=f*10+c-48; while (c=getchar(),c>='0'&&c<='9') f=f*10+c-48; return d*f; } int main() { freopen("past.in"
,"r",stdin); freopen("past.out","w",stdout);//檔案輸入輸出 n=input;m=input;q=input;//輸入 for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) a[i][j]=input;//輸入 while (q--) { x1=input;y1=input;x2=input;y2=input; maxx=-2147483647; for (int i=x1;i<=x2;i++) for (int j=y1;j<=y2;j++) maxx=max(a[i][j],maxx);//直接模擬 printf("%d\n",maxx);//輸出 } return 0; }

第三題 I Like Matrix!

大意

給定k 種移動方式:從(i; j) 移動到(i + xk; j + yk)(xk; yk > 0)。詢問在一個n m 的矩陣中,
從(1; 1) 出發,可以到達多少個位置。
n<=m<=100,k<=10

思路

資料很弱,直接dfs,但是其實bfs會更快

程式碼dfs

#include<cstdio>
#define input read()
#define xh for (int i=1;i<=k;i++)
using namespace std;
int n,m,k;
int l=0;
bool b[101][101]={0};
int x1[21],y1[21];
int ans=1;
int lx[11],lx2[11];
int read()//輸入流
{
    char c;int d=1;int f=0;
    while (c=getchar(),c<'0'||c>'9') if(c=='-')d=-1;f=f*10+c-48;
    while (c=getchar(),c>='0'&&c<='9') f=f*10+c-48;
    return d*f;
}
void dfs(int x,int y,int dep)//dfs
{
    if ((x>n||y>m||x<1||y<1)) return;
    else if (dep!=1)ans++;
    xh
     if (b[x+x1[i]][y+y1[i]]==0&&x+x1[i]<=n&&y+y1[i]<=m&&x+x1[i]>0&&y+y1[i]>0)
     {
        b[x+x1[i]][y+y1[i]]=1;
        dfs(x+x1[i],y+y1[i],dep+1);
        if (b[x][y]) continue;
        b[x+x1[i]][y+y1[i]]=0;//回溯
     }
}
int main()
{
    freopen("present.in","r",stdin);
    freopen("present.out","w",stdout);
    b[1][1]=true;
    n=input;m=input;k=input;
    xh
     {x1[i]=input;y1[i]=input;}
    dfs(1,1,1);//深搜
    printf("%d",ans);
    return 0;
}

程式碼 bfs

#include <cstdio>
using namespace std;
bool f[101][101]; int x,y,n,m,k,ans;
int main(){
    freopen("present.in","r",stdin);
    freopen("present.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k); f[1][1]=true;
    while (k--){
        scanf("%d%d",&x,&y);
        for (int i=1;i<=n;i++)
        if (i+x<=n)
        for (int j=1;j<=m;j++)
        if (j+y<=m)
        if (f[i][j]) f[i+x][j+y]=f[i][j];//一波寬搜
    }
    for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
    if (f[i][j]) ans++;//統計
    printf("%d",ans);//輸出
    return 0;
}

第四題 I Will Like Matrix!

大意

在一個n m 的矩陣A 的所有位置中分別填入0 或1,要求填入的數必須滿足Ai;j Ai;j+1 且
Ai;j Ai+1;j。詢問一共有多少種不同的矩陣,並將答案對1000000007 取模。

思路

一波深搜找規律,發現是楊輝三角,直接過去。
但因為有對1000000007取餘,而1000000007是一個質數,根據費馬小定理也可以加上快速冪求解

dfs程式碼

#include<cstdio>
#define input read()
#define p 1000000007
#define INF 2147483647
using namespace std;
int n,m;
long long ans;
int b[601][601];
int read()
{
    char c;int d=1;int f=0;
    while (c=getchar(),c<'0'||c>'9') if(c=='-')d=-1;f=f*10+c-48;
    while (c=getchar(),c>='0'&&c<='9') f=f*10+c-48;
    return d*f;
}
bool pd()
{
    for (int i=1;i<=n;i++)
     for (int j=1;j<=m;j++)
      {
        if (b[i][j]<=b[i][j+1]&&b[i][j]<=b[i+1][j])continue;
        return true;
      }
    return false;
}
void dfs(int x,int y)
{
    if (pd()) return;
    if (x>n) {ans=(ans+1)%p;return;}
    b[x][y]=1;
    dfs(y==m? x+1:x,y==m? 1:y+1);
    b[x][y]=0;
    dfs(y==m? x+1:x,y==m? 1:y+1);
    b[x][y]=INF;
}
int main()
{
    n=input;m=input;
    int i=600,j=600;
    while (i--)  {while (j--) b[i][j]=INF;j=600;}
    dfs(1,1);
    printf("%d",(ans)%p);
}

楊輝金字塔程式碼

#include<cstdio>
#define input read()
#define p 1000000007
#define INF 2147483647
using namespace std;
int a[2][5001];
int n,m,i;
void swap(int &o,int &k)
{
    int t=o;o=k;k=t;
}
int read()
{
    char c;int d=1;int f=0;
    while (c=getchar(),c<'0'||c>'9') if(c=='-')d=-1;f=f*10+c-48;
    while (c=getchar(),c>='0'&&c<='9') f=f*10+c-48;
    return d*f;
}
int main()
{
    freopen("future.in","r",stdin);
    freopen("future.out","w",stdout);
    n=input;m=input;bool x;bool y;
    if (n>m) swap(n,m);
    for (int i=1;i<=n;i++)
     for (int j=1;j<=m;j++)
      {
        x=i%2;
        y=(i+1)%2;
        if (i==1) {a[x][j]=j+1;continue;}
        if (j==1) {a[x][j]=i+1;continue;}
        a[x][j]=(a[y][j]+a[x][j-1])%p;
      }
    printf("%d",a[x][m]);
    return 0;
}

快速冪+費馬小定理程式碼

#include <cstdio>
using namespace std;
const unsigned long long p=1000000007;
int n,m,i;
void swap(int &a,int &b){int t=a;a=b;b=t;}
unsigned long long s=1;
unsigned long long ksm(unsigned long long x,unsigned long long y){
    unsigned long long result=1;//快速冪
    while (y){
        if (y&1) result=(result*x)%p;
        x=(x*x)%p;
        y>>=1;
    }
    return result;
}
int main(){
    freopen("future.in","r",stdin);
    freopen("future.out","w",stdout);
    scanf("%d%d",&n,&m); n+=m; 
    if (n>m) swap(n,m); 
    for (i=1;i<=n;i++)s=((s*(m-i+1))%p*ksm(i,p-2))%p;//一波快速冪
    printf("%d",s%p);//輸出
    return 0;
}

第五題 I Like Matrix Forever!

大意

對矩陣進行一堆操作,然後要求支援還原歷史版本

思路

“我會主席樹”“滾!”
“我會ROPE”“滾!”
“我會可持久化棧”“滾”

其實這道題並不需要用什麼可持久化資料結構,可以對答案建一顆搜尋樹,由於資料較弱,我們可以直接通過樹直接還原

程式碼

#include<cstdio>
#include<algorithm>
using namespace std;
int read()
{
    char c;int f=0;
    while((c=getchar())<'0'||c>'9');f=(f<<3)+(f<<1)+c-48;
    while((c=getchar())>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return f;
}
void write(int x)
{
    if(x>9) write(x/10);putchar(x%10+48);return;
}
void writeln(int x)
{
    write(x);putchar(10);
}
int n,m,q,k;
struct node
{
    int a,b;
}e[100002];
int x[100002],y[100002],p[100002],opt[100002],ans[100002];
int f[1001][1001];
void swap(int &o,int &k)
{
    o^=k;k=o^k;o^=k;
}
bool cmp(node x,node y){return x.a<y.a;}
void solve(int t)
{
    int i;
    if (opt[t]==1)
    {
        k+=1-(f[x[t]][y[t]]<<1);
        f[x[t]][y[t]]^=1;
    }
    if (opt[t]==2)
        for (i=1;i<=m;i++)
        {
            k+=1-(f[x[t]][i]<<1);
            f[x[t]][i]^=1;
        }
    if (opt[t]==3)
        for (i=1;i<=n;i++)
        {
            k+=1-(f[i][x[t]]<<1);
            f[i][x[t]]^=1;
        }
    ans[t]=k;
    for (i=p[t];i<p[t+1];i++) solve(e[i].b);
    if (opt[t]==1)
    {
        k+=1-2*f[x[t]][y[t]];
        f[x[t]][y[t]]^=1;
    }
    else
    if (opt[t]==2)
        for (i=1;i<=m;i++)
        {
            k+=1-2*f[x[t]][i];
            f[x[t]][i]^=1;
        }
    else
    if (opt[t]==3)
        for (i=1;i<=n;i++)
        {
            k+=1-2*f[i][x[t]];
            f[i][x[t]]^=1;
        }
}
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for (int i=1;i<=q;i++)
    {
        scanf("%d%d",&opt[i],&x[i]);e[i].b=i;
        if (opt[i]==1) scanf("%d",&y[i]);
        if (opt[i]==1||opt[i]==2||opt[i]==3)
         e[i].a=i-1;else e[i].a=x[i];
    }
    sort(e+1,e+1+q,cmp);e[0].a=-1;e[q+1].a=q+1;
    for (int i=1;i<=q+1;i++)
     for (int j=e[i-1].a+1;j<=e[i].a;j++) p[j]=i;
    solve(0);
    for (int i=1;i<=q;i++) writeln(ans[i]);
}