1、给定一个$n*m$的矩阵,里面的数字是1到$n*m$的一个排列。一个$n*m$矩阵$A$对应一个$n*m$ 的01字符串,字符串的位置$i*m+j$为1当且仅当$A_{i,j}=i*m+j+1$。现在可以交换矩阵的两列或者两行。在任意多次操作后使得矩阵对应的字符串最大?
思路:从1到$n*m$,依次枚举。每次将当前数字填回正确位置。比较该次操作前后是否变大。不变大则不做本次操作。
#include <stdio.h> #include <vector> #include <string> using namespace std; class GridSortMax { int a[55][55]; int b[55][55]; int N,M; void reset(int t) { for(int i=0;i<N;++i) for(int j=0;j<M;++j) { if(t==0) b[i][j]=a[i][j]; else a[i][j]=b[i][j]; } } pair<int,int> get(int t) { for(int i=0;i<N;++i) { for(int j=0;j<M;++j) { if(a[i][j]==t) return make_pair(i,j); } } } void swapCol(int y1,int y2) { for(int i=0;i<N;++i) swap(a[i][y1],a[i][y2]); } void swapRow(int x1,int x2) { for(int i=0;i<M;++i) swap(a[x1][i],a[x2][i]); } string getAns() { string s=""; for(int i=0;i<N;++i) for(int j=0;j<M;++j) { if(a[i][j]==i*M+j+1) s+="1"; else s+="0"; } return s; } public: string findMax(int n,int m,vector<int> grid) { for(int i=0;i<n;++i) { for(int j=0;j<m;++j) { a[i][j]=grid[i*m+j]; } } N=n; M=m; for(int i=1;i<=n*m;++i) { pair<int,int> p=get(i); int x=p.first; int y=p.second; int xx=(i-1)/m; int yy=(i-1)%m; if(x==xx&&y==yy) continue; string s0=getAns(); reset(0); if(x!=xx) swapRow(x,xx); if(y!=yy) swapCol(y,yy); string s1=getAns(); if(s1<s0) reset(1); } return getAns(); } };
2、(1)“()”是合法的字符串;(2)如果s是合法的,那么"(sss..ss)"是合法的,即1个或多个s外面加一层圆括号。给定字符串$S$以及 $k$,问$S$的所有合法子列的集合中(不重复),第$k$小的是哪个?$|S|<=150$,$k<=10^{9}$
思路:首先得到所有合法的字符串,然后分别枚举是不是$S$的子列。
#include <string.h> #include <stdio.h> #include <vector> #include <string> #include <set> using namespace std; set<string> s; void dfs(string x) { if(x.size()>150) return; s.insert(x); string p=""; for(int i=0;p.size()<=150;++i) { p+=x; dfs("("+p+")"); } } class RepeatedStrings { public: string findKth(string S,int k) { dfs("()"); for(string x:s) { int p1=0,p2=0; while(p1<(int)S.size()&&p2<(int)x.size()) { if(S[p1]==x[p2]) ++p1,++p2; else ++p1; } if(p2>=(int)x.size()) { if(--k==0) return x; } } return ""; } };