11月12日考试 题解(打表+构造+动态规划)
T1 A
题目大意:给定长度为$n$的序列$a_i$,求$\sum\limits_{p} \frac{1}{a_{p_1}\times (a_{p_1}\times a_{p_2})\times \cdots \times (a_{p_1}\times \cdots \times a_{p_n})}$,其中$p$为$1-n$的排列。
貌似机房里很多人栽这里了。jzp打表;我是手推10分钟性质然后猜了个结论:$ans=\frac{1}{a_1a_2\cdots a_n}$,然后过了……有大佬给出了证明。~~在此略去~~
代码:
#include<cstdio> #include<iostream> #define int long long using namespace std; const int N=100005; const int mod=998244353; int x,ans=1,n; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } inline int qpow(int x,int y) { int res=1; while(y) { if (y&1) res=(res*x)%mod; x=(x*x)%mod; y>>=1; } return res; } signed main() { n=read(); for (int i=1;i<=n;i++) { x=read(); ans=(ans*x)%mod; } printf("%lld",qpow(ans,mod-2)); return 0; }
T2 B
题目大意:在两个 $n\times m$ 的网格上染色,每个网格中被染色的格子必须是一个四联通块(没有任何格子被染色也可以),四联通块是指所有染了色的格子可以通过网格的边联通,现在给出哪些格子在两个网格上都被染色了,保证网格的最外围一层不会在两个网格中同时被染色,即所有处于第 $ x$ 行第 $y$ 列满足$x=1$ 或 $x=n$ 或 $y=1$ 或 $y=m$ 的格子不会被在两个网格中同时被染色,请求出任意一种染色的方案,如果无解,请输出$-1$。
注意到网格的最外围一层不会在两个网格中同时被染色,所以我们可以将第一列分给第一个网格,将最后一列分给第二个网格;然后将行依次交叉分给两个网格,最后把两个网格中都染上色的地方染上色即可。
#include<cstdio> #include<iostream> using namespace std; const int N=505; int a[N][N],b[N][N],n,m; int x[N*N],y[N*N],tot; char mp[N][N]; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%s",mp[i]+1); for (int j=1;j<=m;j++) if (mp[i][j]=='1') x[++tot]=i,y[tot]=j; } for (int i=1;i<=n;i++) a[i][1]=1,b[i][m]=1; for (int i=1;i<=n;i++) for (int j=2;j<=m-1;j++) if (i%2==1) a[i][j]=1; else b[i][j]=1; for (int i=1;i<=tot;i++) a[x[i]][y[i]]=b[x[i]][y[i]]=1; for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) printf("%d",a[i][j]); printf("\n"); } printf("\n"); for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) printf("%d",b[i][j]); printf("\n"); } return 0; }
T3 C
题目大意:给出一个 H 的行和 W 列的网格。第 i 行第 j 列的状态是由一个字母的 A[i][j]表示,如下:“.” 此格为空。“o” 此格包含一个机器人。“E” 此格包含一个出口,保证出口在整个网格中有且只有一个每次可以选择上,下,左,右之一的方向,将所有剩余的机器人向这个方向移动一个格子,如果一个机器人被移出了网格,那么这个机器人会爆炸,并立即消失。如果一个机器人移动到出口所在的格子,机器人将获救,并消失,最多有多少机器人获救。
~~设$f_{l,r,u,d}$表示分别向四个方向走多少步有多少机器人能够获救然后大力转移就好。~~
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N=105; int f[2][N][N][N]; int x[N][N],y[N][N],s[5]; char mp[N][N]; int n,m,ex,ey,l,r,u,d,z,ans; inline int getl(int h1,int h2,int l1) { if (ey-l-1<=r) return 0; return x[min(h1,n-u)][l1]-x[max(h2,d)][l1]; } inline int getr(int h1,int h2,int l1) { if (m-l<=ey+r) return 0; return x[min(h1,n-u)][l1]-x[max(h2,d)][l1]; } inline int getu(int l1,int l2,int h1) { if (ex-u-1<=d) return 0; return y[h1][min(l1,m-l)]-y[h1][max(l2,r)]; } inline int getd(int l1,int l2,int h1) { if (n-u<=ex+d) return 0; return y[h1][min(l1,m-l)]-y[h1][max(l2,r)]; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%s",mp[i]+1); for (int j=1;j<=m;j++) { x[i][j]=x[i-1][j];y[i][j]=y[i][j-1]; if (mp[i][j]=='E') ex=i,ey=j,s[1]=i-1,s[2]=j-1,s[3]=n-i,s[4]=m-j; else if (mp[i][j]=='o') x[i][j]++,y[i][j]++; } } for (l=0;l<=s[2];l++) { z=1-z; memset(f[1-z],0,sizeof(f[1-z])); for (r=0;r<=s[4];r++) for (u=0;u<=s[1];u++) for (d=0;d<=s[3];d++) { f[z][r][u][d+1]=max(f[z][r][u][d+1],f[z][r][u][d]+getd(ey+r,ey-l-1,ex+d+1)); f[z][r][u+1][d]=max(f[z][r][u+1][d],f[z][r][u][d]+getu(ey+r,ey-l-1,ex-u-1)); f[z][r+1][u][d]=max(f[z][r+1][u][d],f[z][r][u][d]+getr(ex+d,ex-u-1,ey+r+1)); f[1-z][r][u][d]=max(f[1-z][r][u][d],f[z][r][u][d]+getl(ex+d,ex-u-1,ey-l-1)); ans=max(ans,f[z][r][u][d]); } } printf("%d",ans); return 0; }