A、九峰与签到题
使用set把过程中全部低于50通过率的题目统计一下就行了。
#include <bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) #define all(__vv__) (__vv__).begin(), (__vv__).end() #define endl "\n" #define pai pair<int, int> #define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__)) #define rep(i, sta, en) for(int i=sta; i<=en; ++i) #define repp(i, sta, en) for(int i=sta; i>=en; --i) typedef long long ll; typedef unsigned long long ull; typedef long double ld; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op) putchar(op); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); if (op) putchar(op); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; const int N = 1e6 + 7; struct Node { ll val; int id; bool operator < (const Node& opt) const { return val < opt.val; } }; ll n, m; int ac[N], sub[N]; void solve() { js; cin >> m >> n; string s; int id; set<int> st; while (m--) { cin >> id >> s; if (s == "AC") ++ac[id]; ++sub[id]; if (!st.count(id) and ac[id] < (sub[id] + 1) / 2) st.insert(id); } if (st.size() == n) cout << "-1"; else { rep(i, 1, n) { if (st.count(i) == 0) cout << i << " "; } } } int main() { //int T = read(); while (T--) solve(); return 0; }
J、邬澄瑶的公约数
发现我们要找到的全部数的,那么我们把全部的数分解质因数,拿到全部的因子。
我们知道数可以分成
我们使用两个计数器,分别统计在不同中质数的出现次数,以及出现的幂次。那么如果一个质数一共出现 n 次我们才能在中拿到这个质数,并且贡献就是出现幂次最小的哪个。
const int N = 1e4 + 7; vector<int> prime; bool vis[N]; void getprime() { vis[1] = 1; rep(i, 2, N - 1) { if (!vis[i]) prime.push_back(i); for (auto& it : prime) { if (it * i >= N) break; vis[it * i] = 1; if (i % it == 0) break; } } } ll n, m; ll x[N], p[N]; void solve() { n = read(); rep(i, 1, n) x[i] = read(); rep(i, 1, n) p[i] = read(); map<int, ll> mp1, mp2; rep(i, 1, n) { ll tmp = x[i]; for (auto& it : prime) { if (it > tmp) break; if (tmp % it == 0) { ++mp1[it]; int cnt = 0; while (tmp % it == 0) ++cnt, tmp /= it; if (mp2.count(it)) mp2[it] = min(mp2[it], cnt * p[i] % MOD); else mp2[it] = cnt * p[i] % MOD; } } } ll ans = 1; for (auto& it : prime) { if (!mp1.count(it)) continue; if (mp1[it] != n) continue; ans = ans * qpow(it, mp2[it], MOD) % MOD; } print(ans); }
B、武辰延的字符串
字符串匹配我们有hash办法做到。
那么对于给出的字符串S和T,我们枚举他们公共前缀,接下来还需要使用另一个S的前缀拼接到后面和T一致。比如我们看
aaab aabb 1、我们枚举第一个字符串就选a,那么接下来就要判断第二个字符串除掉a也就是剩下abb 和第一个字符串最长的匹配长度是多少,显然只能是1,因为a+a=a+a,a+aa!=a+ab 2、我们枚举第一个字符串选aa,接下来去找第二个字符串除掉aa剩下的和第一个字符串 的最长公共前缀,显然答案是0,因为只有aa=aa,aa+a!=aa+b 3、我们枚举第一个字符串选aaa,因为第二个字符串aab!=aaa,所以后面都不需要枚举了,直接退出即可
我们发现只需要判断长度,具有单调性,使用二分优化。时间复杂度就可以到。
当然如果你学会了exkmp,你会发现它就是干这个事的,它的next数组就是求得和前面串的最长公共前缀长度,直接累加一下就是答案了,时间复杂度可以优化到。
ll n, m; char s1[N], s2[N]; ull has1[N], has2[N], p[N], bas = 131; ull query1(int l, int r) { return has1[r] - has1[l - 1] * p[r - l + 1]; } ull query2(int l, int r) { return has2[r] - has2[l - 1] * p[r - l + 1]; } void solve() { scanf("%s %s", s1 + 1, s2 + 1); p[0] = 1; rep(i, 1, N - 1) p[i] = p[i - 1] * bas; n = strlen(s1 + 1); m = strlen(s2 + 1); rep(i, 1, n) has1[i] = has1[i - 1] * bas + (s1[i] - 'a'); rep(i, 1, m) has2[i] = has2[i - 1] * bas + (s2[i] - 'a'); ll ans = 0; rep(i, 1, n) { if (s1[i] != s2[i]) break; int l = i + 1, r = m, res = 0; while (l <= r) { int mid = l + r >> 1; ull a = query1(1, mid - i); ull b = query2(i + 1, mid); if (a == b) res = mid - i, l = mid + 1; else r = mid - 1; } ans += res; } print(ans); }
G、九峰与蛇形填数
发现每次后面的会覆盖前面的,说明前面填的数后面又填了,那么前几次都是无用功。
那么我们从后往前遍历输入的填数顺序,使用一个数组记录答案,一个数组记录位置下一个没填的在什么地方。这样就可以保证每个位置最多遍历一遍。复杂度有
const int N = 2000 + 7; const int M = 3000 + 7; ll n, m; int s[N][N]; int l[N][N]; int p[4][M]; void solve() { n = read(), m = read(); rep(i, 1, m) rep(j, 1, 3) p[j][i] = read(); repp(i, m, 1) { int sti = p[1][i], stj = p[2][i]; int edi = sti + p[3][i] - 1, edj = stj + p[3][i] - 1; rep(j, sti, edi) { rep(k, stj, edj) { int x; if ((j - sti) & 1) x = (j - sti + 1) * p[3][i] - (k - stj); else