2017年11月1日普及組模擬賽【解題報告】
阿新 • • 發佈:2019-01-07
第一題 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!
大意
給定一個 的矩陣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) 出發,可以到達多少個位置。
思路
資料很弱,直接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]);
}