轮到罗剑桥出题了
这是什么风格,中文名称与英文名称分明对不上吗233
T1:
似乎只会做这道题23333
A....BE
........
C....DF
据题意数学变形得A-C<=B-D,B-D<=E-F,即左右的差是递增的。
A....B
.......
C....D
E....F
据题意数学变形得A-B<=C-D,C-D<=E-F,即上下的差是递增的。
那么令f1[i][j]=A[i][j]-A[i+1][j],f2[i][j]=A[i][j]-A[i][j+1]。
只有当f1[i][j-1]<=f1[i][j]且f2[i-1][j]<=f2[i][j]时 (i,j)才能进入矩形中。
那么问题就转化成最大子矩形,其内部没有坏点。
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=1010; int A[maxn][maxn],B[maxn][maxn],C[maxn][maxn],n,m,ans; int is[maxn][maxn]; int right[maxn],left[maxn],up[maxn][maxn]; int main() { freopen("neo.in","r",stdin); freopen("neo.out","w",stdout); n=read();m=read(); rep(i,1,n) rep(j,1,m) A[i][j]=read(); rep(i,1,n) rep(j,1,m) B[i][j]=A[i][j]-A[i+1][j],C[i][j]=A[i][j]-A[i][j+1]; n--;m--; rep(i,1,n) rep(j,1,m) if(B[i][j]<=B[i][j+1]&&C[i][j]<=C[i+1][j]) is[i][j]=1; rep(i,1,n) { rep(j,1,m) { if(!is[i][j]) continue; up[i][j]=up[i-1][j]+1; if(j==1) left[j]=1; else { left[j]=j; while(up[i][left[j]-1]>=up[i][j]) left[j]=left[left[j]-1]; } } for(int j=m;j;j--) { if(!is[i][j]) continue; if(j==m) right[j]=m; else { right[j]=j; while(up[i][right[j]+1]>=up[i][j]) right[j]=right[right[j]+1]; } ans=max(ans,(up[i][j]+1)*(right[j]-left[j]+2)); } } printf("%d ",ans); return 0; }
T2:简要题意,计算从最上角上方连一条管道到最下角下方的方案书数。
显然是不可做的插头DP,写个暴搜60
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=15; int n,m,ans; char A[maxn][maxn]; int have[maxn][maxn]; int mx[]={1,-1,0,0},my[]={0,0,1,-1}; void dfs(int x,int y) { have[x][y]=1; if(x==n&&y==m) ans++; else rep(dir,0,3) if(x>=1&&x<=n&&y>=1&&y<=m&&!have[x+mx[dir]][y+my[dir]]&&A[x+mx[dir]][y+my[dir]]=='.') dfs(x+mx[dir],y+my[dir]); have[x][y]=0; } int main() { freopen("voda.in","r",stdin); freopen("voda.out","w",stdout); n=read();m=read(); rep(i,1,n) scanf("%s",A[i]+1); if(A[1][1]=='#'||A[n][m]=='#') {puts("0");return 0;} dfs(1,1);printf("%d ",ans%10007); return 0; }
T3:有一个N层M格的书架,可以将一本书移动到另一层,也可以把同一层的书左右移动,求从初始状态到最终状态的最少移动数。
考虑那些前后所在层不变的书,应对答案贡献总数-LCS的数目,如果这层全满,需要答案额外+1(先将一本拿到别层再拿回来)。
对于前后所在层变化的书,答案要+1表示移动一次,如果所在连通分量全满,同理答案要再+1.
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=1010; int m,C[maxn],t[maxn*maxn],g[maxn]; int get(int* C,int len) { int ans=0; rep(i,1,len) g[i]=1<<30; rep(i,1,len) { int k=lower_bound(g+1,g+len+1,C[i])-g; ans=max(ans,k);g[k]=C[i]; } return ans; } int n,A[maxn][maxn],B[maxn][maxn],yes[maxn],ans; int pos[maxn*maxn],pos2[maxn*maxn],first[maxn],next[maxn*maxn*2],to[maxn*maxn*2],e; void AddEdge(int u,int v) { ans++; to[++e]=v;next[e]=first[u];first[u]=e; to[++e]=u;next[e]=first[v];first[v]=e; } int vis[maxn],f[maxn]; int dfs(int x) { if(vis[x]) return f[x];vis[x]=1; int& ans=f[x];ans=!yes[x]; for(int i=first[x];i;i=next[i]) ans&=dfs(to[i]); return ans; } int main() { freopen("police20.in","r",stdin); freopen("police.out","w",stdout); n=read();m=read();int ok=0,dif=0; rep(i,1,n) rep(j,1,m) { A[i][j]=read(); if(!A[i][j]) ok=yes[i]=1; else pos[A[i][j]]=i,pos2[A[i][j]]=j; } rep(i,1,n) rep(j,1,m) { B[i][j]=read(); if(B[i][j]&&i!=pos[B[i][j]]) AddEdge(i,pos[B[i][j]]); } rep(i,1,n) { int len=0; rep(j,1,m) if(B[i][j]&&pos[B[i][j]]==i) C[++len]=pos2[B[i][j]]; int tmp=len-get(C,len); if(tmp) ans+=tmp+(len==m); } if(ans&&!ok) puts("-1"); else { rep(i,1,n) if(!vis[i]&&first[i]) ans+=dfs(i); printf("%d ",ans); } return 0; }