1、给定一个迷宫,点号表示不可行,井号表示可行。现在可以改变其中的一些井号的位置。问最少改变多少个井号可以使得从左上角到右下角存在路径。
思路:设高为$n$,宽为$m$,若井号的个数$S$小于$n+m-1$则无解。否则最多改变$n+m-1$个井号即可。令$f[x][y][k]$表示现在到达位置$(x,y)$且中途经过的点号格子数为$k$时最少经过了多少井号格子。这样进行搜索即可。搜过过程中,应该满足$k\leq n+m-1$且$k+f[x][y][k]\leq S$。
#include <iostream> #include <set> #include <stdio.h> #include <queue> #include <algorithm> #include <string.h> using namespace std; const int N=20; int f[N][N][N+N]; int inq[N][N][N+N]; int h[N][N][N+N]; const int dx[]={0,0,1,-1}; const int dy[]={1,-1,0,0}; struct node { int x,y,p; node(){} node(int _x,int _y,int _p): x(_x),y(_y),p(_p) {} }; queue<node> Q; void add(int x,int y,int p,int c) { if(!h[x][y][p]||f[x][y][p]>c) { h[x][y][p]=1; f[x][y][p]=c; if(!inq[x][y][p]) { inq[x][y][p]=1; Q.push(node(x,y,p)); } } } class MovingCandies { public: int minMoved(const vector<string> t) { const int n=(int)t.size(); const int m=(int)t[0].size(); int S=0; for(int i=0;i<n;++i) for(int j=0;j<m;++j) S+=t[i][j]==‘#‘; if(S<n+m-1) return -1; if(t[0][0]==‘.‘) add(0,0,1,0); else add(0,0,0,1); while(!Q.empty()) { const int x=Q.front().x; const int y=Q.front().y; const int p=Q.front().p; const int c=f[x][y][p]; Q.pop(); inq[x][y][p]=0; if(x==n-1&&y==m-1) continue; for(int d=0;d<4;++d) { const int xx=x+dx[d]; const int yy=y+dy[d]; if(xx>=0&&xx<n&&yy>=0&&yy<m) { const int pp=p+(t[xx][yy]==‘.‘); const int cc=c+(t[xx][yy]==‘#‘); if(pp>n+m-1||pp+cc>S) continue; add(xx,yy,pp,cc); } } } for(int i=0;i<=n+m-1;++i) { if(h[n-1][m-1][i]) return i; } return -1; } };
2、给定一个整数数组,每个数字可以被替换成字符ABC中的一个,相同的数组必须被相同的字符替换。问在被任意替换得到的所有不同的字符串中,包含子列ABC的串有多少个。
思路:一个简单的思路是分别枚举第一个A、第一个B、第一个C出现的位置,这样整个串被分成4部分,第一部分中不能出现A,第二部分不能出现B,第三部分不能出现C。这样复杂度是$O(N^{3})$。现在只枚举第一个A第一个B,然后后面字符任意的总数为$X$,不包含C的总数为$Y$,那么此次枚举对答案的贡献为$X-Y$。这样是$O(N^{2})$的复杂度。实现如代码所示。其中$f[i][j]=0$表示数字$i$可以被替换成字符$j$,$j=0$表示A,$j=1$表示B,$j=2$表示C。$tot[j]$表示有多少种数字有$j$种替换方式。
#include <string.h> #include <stdio.h> #include <vector> using namespace std; const int mod=1000000007; const int N=3005; int p[4][N]; int tot[4]; int f[N][4]; int appears[N]; class MappingABC { void init() { for(int i=0;i<4;++i) { p[i][0]=1; for(int j=1;j<N;++j) p[i][j]=((long long)p[i][j-1]*i%mod); } } void clear() { memset(f,0,sizeof(f)); memset(tot,0,sizeof(tot)); } int get() { int ans=1; for(int i=0;i<4;++i) ans=((long long)ans*p[i][tot[i]]%mod); return ans; } int cal(int x) { int c=0; for(int i=0;i<3;++i) if(f[x][i]==0) ++c; return c; } void add(int x,int y) { --tot[cal(x)]; ++f[x][y]; ++tot[cal(x)]; } void sub(int x,int y) { --tot[cal(x)]; --f[x][y]; ++tot[cal(x)]; } public: int countStrings(vector<int> t) { const int n=(int)t.size(); for(int i=0;i<n;++i) appears[t[i]]=1; init(); int ans=0; const int A=0,B=1,C=2; for(int k=0;k<2;++k) { const int NO_C=k==1; for(int a=0;a<n;++a) { clear(); for(int i=0;i<N;++i) if(appears[i]) ++tot[3]; for(int i=0;i<a;++i) add(t[i],A); add(t[a],B); add(t[a],C); if(NO_C) { for(int i=a+1;i<n;++i) add(t[i],C); } for(int b=a+1;b<n;++b) { if(NO_C) sub(t[b],C); add(t[b],A); add(t[b],C); if(NO_C) ans=(ans-get())%mod; else ans=(ans+get())%mod; sub(t[b],A); sub(t[b],C); add(t[b],B); } } } if(ans<0) ans+=mod; return ans; } };
时间: 2024-10-05 16:01:56