题解:
第一题:
20%枚举长度和每个子串,O(len)判断,随机情况复杂度可过
40%同样枚举长度,然后两个指针卡出区间,O(1)[或O(26)//可能可过?]判断
50%既然知道了40%的做法那么我们可以二分长度就好了
70%二分,需要O(1)判断
100%两个指针维护一个区间,保证左端点固定时,是最小的完美子串
开桶记录每个出现多少次,当一个点新加入或消失时,tot对应改变,tot=26时,更新答案,复杂度O(n)
#include<bits/stdc++.h> using namespace std; const int M = 2e6 + 10; char a[M]; int len, s[M], vis[28]; bool check(int k){ int ret = 0; memset(vis, 0, sizeof(vis)); for(int i = 1; i <= k; i++){ if(!vis[s[i]])ret++; vis[s[i]]++; } if(ret >= 26)return 1; for(int i = k + 1; i <= len; i++){ vis[s[i - k]]--; if(!vis[s[i - k]])ret--; if(!vis[s[i]])ret++; vis[s[i]]++; if(ret >= 26)return 1; } return 0; } int main(){ freopen("str.in","r",stdin); freopen("str.out","w",stdout); scanf("%s", a); len = strlen(a); if(len < 26){ printf("QwQ "); return 0; } for(int i = 0; i < len; i++)s[i + 1] = a[i] - 'A'; int lf = 26, ans = 0, rg = len; while(lf <= rg){ int mid = (lf + rg) >> 1; if(check(mid))ans = mid, rg = mid - 1; else lf = mid + 1; } if(!ans)printf("QwQ "); else printf("%d ",ans); }
第二题:
将两个数相乘,看一看是不是一个数的立方,我们可以把游戏压缩成两局,变成X1^1 * X2^1 * …… * Yn-1 ^2 * Yn^2 X1 ^ 2 * X2 *^ 2 * ……* Yn-1 ^ 1 * Yn ^1, 所以他一定是一个数k的三次方; 再看拆出来的k是不是x, y 的因数
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 1; #define ll long long ll x, y; bool check(){ ll tmp = x * y; ll lf = 1, ans = 0, rg = min(sqrt(tmp), 1e6); while(lf <= rg){ ll mid = (lf + rg) >> 1; ll cc = mid * mid * mid; if(cc == tmp) {ans = mid; return (x % mid == 0 && y % mid == 0);} if(cc < tmp)lf = mid + 1; else rg = mid - 1; } return 0; } int main(){ freopen("game.in","r",stdin); freopen("game.out","w",stdout); int T; scanf("%d", &T); while(T--){ scanf("%I64d%I64d", &x, &y); if(check())puts("Yes"); else puts("No"); } }
第三题:
不能盖住好地,那么宽为1的木板只能放在行、列连通块里。
•所以行、列连通块对应左、右部中的点,泥地对应边。
•求二分图最小覆盖就是答案。
二分图最小点覆盖==最大匹配
#include<bits/stdc++.h> using namespace std; const int M = 101; char c[M][M]; int mp[M][M]; bool vis[M*M*2]; int head[M*M*2], h[M][M], r[M*M*2], l[M][M], lf[M*M], num, tot, match[M*M*2]; struct edge{int v, nxt;}G[M*M*2]; void add(int u, int v){G[++tot].nxt = head[u]; head[u] = tot; G[tot].v = v;} bool find(int u){ for(int i = head[u]; i; i = G[i].nxt){ int v = G[i].v; if( !vis[v] ){ vis[v] = 1; if(!match[v] || find(match[v])){ match[v] = u; return 1; } } } return 0; } int main(){ freopen("cover.in","r",stdin); freopen("cover.out","w",stdout); int R, C, ans = 0, cnt = 0; scanf("%d%d", &R, &C); for(int i = 1; i <= R; i++)scanf("%s", c[i]); for(int i = 1; i <= R; i++) for(int j = 0; j < C; j++){ if(c[i][j] =='*')mp[i][j + 1] = 1;//, id[i][j + 1] = ++num; } for(int i = 1; i <= R; i++) for(int j = 1; j <= C; j++){ if(!h[i][j]){ ++num; for(int k = j; k <= C && mp[i][k]; k++){ h[i][k] = num; //add(id[i][k], num); } } if(!l[i][j]){ ++num; for(int k = i; k <= R && mp[k][j]; k++){ l[k][j] = num; //add(id[k][j], num); } } } for(int i = 1; i <= R; i++) for(int j = 1; j <= C; j++) if(mp[i][j]){ add(h[i][j], l[i][j]); if(!r[h[i][j]]){ lf[++cnt] = h[i][j]; r[h[i][j]] = 1; } } for(int i = 1; i <= cnt; i++){ memset(vis, 0, sizeof(vis)); if(find(lf[i]))ans++; } printf("%d ", ans); }