题意
有一个用字符类型表示的 行
列的地图 ,如果 是字符 .
则代表这一格是空地,如果是 #
则代表这一格上有一个磁铁。现在身着铁甲的高桥从一个格子上出发,每次可以到达与之相邻(上、下、左、右)的四个格子,但如果有一个磁铁与之相邻(上下左右的四个格子中至少有一个磁铁)他就不能动了。求高桥从某一格出发,经过任意多次运动,可以到达的格子的最大数量(即最大连通块)。
解题思路
一个格子不可能同时出现两个不同的连通块中 ,由此我们可以通过枚举连通块:从未被搜索的格子出发,然后向四周扩展,将可达的格子打上标记(表示属于当前连通块),并用 记录可达格子的数量(即:连通块的大小),最终答案 ,每个格子最多只能被搜索一次,由此时间复杂度为
解题代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <bits/stdc++.h> using namespace std;const int N=1010 ;int n,m; string s[N];int dx[4 ]={-1 ,0 ,1 ,0 },dy[4 ]={0 ,1 ,0 ,-1 };int vis[N][N];int now_cnt,now,ans;bool valid (int x,int y) { if (x<0 ||x>=n||y<0 ||y>=m) return false ; return true ; }bool is_move (int x, int y) { for (int i=0 ;i<4 ;i++){ int nxt_x=x+dx[i],nxt_y=y+dy[i]; if (valid (nxt_x,nxt_y)&&s[nxt_x][nxt_y]=='#' ) return false ; } return true ; }void dfs (int x,int y) { now_cnt++; vis[x][y]=now; if (!is_move (x,y)) return ; for (int i=0 ;i<4 ;i++){ int nxt_x=x+dx[i],nxt_y=y+dy[i]; if (!valid (nxt_x,nxt_y)) continue ; if (vis[nxt_x][nxt_y]==now) continue ; dfs (nxt_x,nxt_y); } }int main () { ios::sync_with_stdio (0 ),cin.tie (0 ),cout.tie (0 ); cin>>n>>m; for (int i=0 ;i<n;i++) cin>>s[i]; for (int i=0 ;i<n;i++){ for (int j=0 ;j<m;j++){ if (s[i][j]=='.' &&!vis[i][j]){ now_cnt=0 ,now++; dfs (i,j); ans=max (ans,now_cnt); } } } cout<<ans<<"\n" ; return 0 ; }
题意
位置 (𝑥,𝑦) 可以一步跳到 (𝑥+1,𝑦+1) 、 (𝑥+1,𝑦−1) 、 (𝑥−1,𝑦+1) 或
(𝑥−1,𝑦−1),即:每一步只能沿对角线走
求解 , 被定义为从 点跳到 点所需的最少跳跃次数(如果 )
解题思路
由于只能沿着对角线移动,那么能从 必须满足: 和 的奇偶性相同,因此我们只需将奇偶性相同的点分为一组,然后只需计算每组组内点 的 即可
不难发现: ,然而这样就对转化的最值求和时间开销依然十分大
这里就不得不引入 (切比雪夫距离与曼哈顿距离的互化),来对时间复杂度进行优化
设平面中两点分别为
一个点 的坐标变为 后,原坐标系中曼哈顿距离
=新坐标系中切比雪夫距离。
一个点 的坐标变为
后,原坐标系中的切比雪夫距离为新坐标系中的曼哈顿距离。
由此我们可以通过变换坐标系,将直角坐标系的点 映射至新坐标系中点 即可转化为曼哈顿距离来做,然后我们计算对新坐标系的的横纵坐标进行从小到大排序(达到:将绝对值符号去掉),最后计算每个横纵坐标产生的贡献值,累加贡献值即为答案
解题代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <bits/stdc++.h> using namespace std;typedef long long ll;int main () { ios::sync_with_stdio (0 ),cin.tie (0 ),cout.tie (0 ); int n;cin>>n; vector<int > a[4 ]; for (int i=0 ;i<n;i++){ int x,y;cin>>x>>y; if ((x+y)&1 ){ a[0 ].push_back (x+y); a[1 ].push_back (x-y); }else { a[2 ].push_back (x+y); a[3 ].push_back (x-y); } } ll ans=0 ; for (int i=0 ;i<4 ;i++){ sort (a[i].begin (),a[i].end ()); int sz=a[i].size (); for (int j=0 ;j<sz;j++){ ans+=1ll *(2 *j+1 -sz)*a[i][j]; } } cout<<ans/2 <<"\n" ; return 0 ; }
题意
对于非负整数序列,求解
解题思路
求解 , 可以分别开两个树状数组维护,需要注意的是:有可能 比较大,因此需要对 进行离散化
总的时间复杂度为
解题代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <bits/stdc++.h> using namespace std;typedef long long ll;const int N=400010 ; ll a[N],n; ll ans;struct BIT { ll d[N]; void update (ll x,ll y) { x++; while (x<N) d[x]+=y,x+=(x&(-x)); } ll query (ll x) { x++; ll sum=0 ; while (x) sum+=d[x],x-=(x&(-x)); return sum; } }bit1,bit2;int main () { ios::sync_with_stdio (0 ),cin.tie (0 ),cout.tie (0 ); cin>>n; vector<ll> new_a (n) ; for (int i=0 ;i<n;i++) cin>>a[i],new_a[i]=a[i]; sort (new_a.begin (),new_a.end ()); new_a.erase (unique (new_a.begin (),new_a.end ()),new_a.end ()); for (int i=0 ;i<n;i++){ int x=lower_bound (new_a.begin (),new_a.end (),a[i])-new_a.begin (); ans+=bit1.query (x)*a[i]-bit2.query (x); bit1.update (x,1 ); bit2.update (x,a[i]); } cout<<ans<<"\n" ; }