一天跟了三场比赛;记录一下部分题目;
https://ac.nowcoder.com/acm/contest/24803/D
nxn的矩阵只能旋转最外面一层,问最后能不能使得整体有序;
可以把最外层全部抠出来,然后可以观察到,他和有序的最外层的最小表示实际上是一样的,如果外面相等,里面可以按照顺序判断,复杂度n*n,(数据范围只有10,感觉可以开到1000.。。)
const int N = 20; int g[N][N]; int d[N][N]; vector<int> v; vector<int> get_min(vector<int>& s) { int n = s.size(); for (int i = 0; i < n; i++) s.push_back(s[i]); int i = 0, j = 1, k = 0; while (i < n and j < n) { for (k = 0; s[i + k] == s[j + k] and k < n; k++); if (k == n) break; if (s[i + k] > s[j + k]) { i += k + 1; if (i == j) i++; } else { j += k + 1; if (i == j) j++; } } k = min(i, j); vector<int> v; for (int i = k; i < k + n; i++) v.push_back(s[i]); return v; } int n; vector<int> init1() { vector<int> v; for (int i = 1; i <= n; i++) { v.eb(d[1][i]); } for (int i = 2; i <= n; i++) { v.eb(d[i][n]); } for (int i = n - 1; i >= 1; i--) { v.eb(d[n][i]); } for (int i = n - 1; i >= 2; i--) { v.eb(d[i][1]); } return v; } void solve() { cin >> n; int idx = 0; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>d[i][j]; } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { g[i][j] = ++idx; } } for (int i = 1; i <= n; i++) { v.eb(g[1][i]); } for (int i = 2; i <= n; i++) { v.eb(g[i][n]); } for (int i = n - 1; i >= 1; i--) { v.eb(g[n][i]); } for (int i = n - 1; i >= 2; i--) { v.eb(g[i][1]); } auto v1 = init1(); if (get_min(v) == get_min(v1)) { int cnt=0; bool ok=true; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ ++cnt; if(i==1 or i==n or j==1 or j==n) continue; if(d[i][j]!=cnt) ok=false; } } if(ok) cout<<"YES"<<endl; else cout<<"NO"<<endl; } else cout << "NO" << endl; }
https://ac.nowcoder.com/acm/contest/24803/B
问一个字母出现k次且最短的序列长度是多少
可以双指针也可以二分
#include <bits/stdc++.h> #define eb emplace_back #define divUp(a,b) (a+b-1)/b #define mkp(x,y) make_pair(x,y) #define all(v) begin(v),end(v) #define int long long #define deb(x) cout<<#x<<" "<<x<<endl #define fi first #define se second using namespace std; typedef pair<int, int> pii; bool checkP2(int n) {return n > 0 and (n & (n - 1)) == 0;}; const int N=100010; char s[N]; int c[30]; int cnt[30]; void solve() { int m; cin>>(s+1); int n=strlen(s+1); memset(c,0,sizeof c); cin>>m; int res=2e9; for(int i=1;i<=n;i++) c[s[i]-'a']++; for(int i=0;i<26;i++){ if(c[i]>=m){ memset(cnt,0,sizeof cnt); for(int j=1,k=1;j<=n;j++){ while(cnt[i]<m and k<=n) { if(s[k]==i+'a') cnt[i]++; k++; } if(cnt[i]>=m) { res=min(res,k-j); } if(s[j]==i+'a') cnt[i]--; } } } if(res==2e9) cout<<-1<<endl; else cout<<res<<endl; } signed main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int _; cin >> _; while (_--) solve(); return 0; }
https://atcoder.jp/contests/abc229/tasks/abc229_dhttps://atcoder.jp/contests/abc229/tasks/abc229_d
一个序列只有x和.最多可以花费k次把.变成x,问连续x的最长序列长度是多少
发现可以二分序列长度,只要再这个长度内花费小于等于k即可,利用前缀和统计x就可以知道.的个数
const int N = 200010; char s[N]; int sum[N]; int k; int n; bool check(int mid) { for (int i = mid, j = 1;i <= n;i++, j++) { int cur = sum[i] - sum[j - 1]; int len = i - j + 1; if (len - cur <= k) { return true; } } return false; } void solve() { cin >> (s + 1)>>k; n=strlen(s+1); for (int i = 1;i <= n;i++) { if (s[i] == 'X') sum[i] = 1; sum[i] += sum[i - 1]; } int l = 0, r = n; while (l < r) { int mid = (l + r + 1) >> 1; if (check(mid)) l = mid; else r = mid - 1; } cout << l << endl; }
https://atcoder.jp/contests/abc229/tasks/abc229_e
给了一个图,每次按照顺序删除编号为i的点,问删除第i个点之后的连通块有多少
求连通块的话很明显可以用并查集,但是每次按照顺序的话,后面删除操作比较困难,所以可以选择倒着跑,每次加进来一个点,如果发现这个点的根节点是他自己,就说明这是一个新的块,每个父节点可以使用set来记录,也方便删除,还有注意一点,加边的时候是较小的边指向较大的边,考虑较大边的时候较小边已经被删除;
int p[N]; int find(int x){ if(x!=p[x]) p[x]=find(p[x]); return p[x]; } set<int> s; pii a[N]; int ans[N]; void merge(int x,int y){ int pa=find(x),pb=find(y); if(pa!=pb){ p[pa]=pb; s.erase(pa); } } vector<int> h[N]; void solve() { int n,m; cin>>n>>m; int x,y; for(int i=1;i<=m;i++){ cin>>x>>y; h[min(x,y)].eb(max(x,y)); } for(int i=1;i<=n;i++) p[i]=i; for(int i=n;i>=1;i--){ ans[i]=s.size(); if(find(i)==i) s.insert(i); for(auto j:h[i]){ merge(i,j); } } for(int i=1;i<=n;i++) cout<<ans[i]<<endl; }
leetcode双周赛66T4
给定一个矩阵,让你找到所有的正金字塔和倒金字塔,(底边是3,5,7,9.。。。);
直接暴力查找,使用前缀和做优化即可
class Solution { public: vector<vector<int>> g,d; int n,m; int sum(int x,int y,int cnt){ if(x>=n or y<0 or y+cnt>=m) return 0; if(!d[x][y]) return 0; if(g[x][y+cnt]-g[x][y]!=cnt) return 0; return sum(x+1,y-1,cnt+2)+1; } int sum1(int x,int y,int cnt){ if(x<0 or y<0 or y+cnt>=m) return 0; if(!d[x][y]) return 0; if(g[x][y+cnt]-g[x][y]!=cnt) return 0; return sum1(x-1,y-1,cnt+2)+1; } int countPyramids(vector<vector<int>>& grid) { d=grid; g=grid; m=grid[0].size(); n=grid.size(); int res=0; for(int i=0;i<n;i++){ g[i][0]=grid[i][0]; for(int j=1;j<m;j++){ g[i][j]=grid[i][j]+g[i][j-1]; } } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(grid[i][j]){ res+=sum1(i,j,0)-1+sum(i,j,0)-1; } } } return res; } };