牛客练习赛25
A 因数个数和
ps:模板题
LL ac(int n) { LL ans=0; for(int i=1,temp;i<=n;i=temp+1) { temp=n/(n/i); ans+=(n/i)*(temp-i+1); } return ans; }
B 最长区间
题解:线段树维护区间左端点,右端点,中间部分的最长递增子区间的长度。
inline void upd(int &x, int y) { x < y && (x = y); } const int N = 100005; int n, m, tot; int L[4 * N], R[4 * N], sum[4 * N], b[N]; void Pushup(int l, int r, int root) { int mid = (l + r) >> 1; L[root] = L[lson]; if (L[lson] == mid - l + 1 && b[mid] < b[mid + 1]) L[root] += L[rson]; R[root] = R[rson]; if (R[rson] == r - mid && b[mid] < b[mid + 1]) R[root] += R[lson]; sum[root] = max(sum[lson], sum[rson]); if (b[mid] < b[mid + 1]) upd(sum[root], L[rson] + R[lson]); //cout << root << " " << L[root] << " " << R[root] << " " << sum[root] << endl; } void Build(int l, int r, int root) { if (l == r) { int x; sc(x); b[++tot] = x; L[root] = R[root] = sum[root] = 1; return; } int mid = (l + r) >> 1; Build(l, mid, lson); Build(mid + 1, r, rson); Pushup(l, r, root); } void Update(int l, int r, int root, int pos, int x) { if (l == r) { b[pos] = x; return; } int mid = (l + r) >> 1; if (pos <= mid) Update(l, mid, lson, pos, x); else Update(mid + 1, r, rson, pos, x); Pushup(l, r, root); } int main() { sc(n), sc(m); Build(1, n, 1); int res = max(sum[1], max(L[1], R[1])); pr(res); res = 0; while(m--) { int pos, x; sc(pos), sc(x); Update(1, n, 1, pos, x); res = max(sum[1], max(L[1], R[1])); pr(res); } return 0; }
C 再编号
ps:找规律,每一项出现的次数是能递推的。
const int N = 100005; const LL mod = 1000000007; int n, m; LL a[N], s[N]; void Inite() { a[1] = 0; rep(i, 2, N) { if (i & 1) a[i] = ((n - 1) * a[i - 1] % mod - n + 1 + mod) % mod; else a[i] = ((n - 1) * a[i - 1] % mod + n - 1) % mod; } } int main() { cin >> n >> m; Inite(); LL sum = 0; Rep(i, 1, n) cin >> s[i], sum += s[i]; sum %= mod; while(m--) { int x, t; sc(x), sc(t); if (!t) { printf("%lld\n", s[x]); } else { LL ans; if (t & 1) { ans = ((a[t] + 1) * sum % mod - s[x] + mod) % mod; } else { ans = ((a[t] - 1) * sum % mod + s[x]) % mod; } printf("%lld\n", ans); } } return 0; }
D a-贝利福斯数
ps:ax + 1 = (ay + 1)(az + 1),x = ayz + y + z,{ x,y,z∈(1,2,3,······,d)},看见这种式子想到了线性筛法,然而实现不了,orz。
暴力枚举,加一个小优化:i 一定是没被标记过数。
void Inite(int m) { for (LL i = 1; i <= m; ++i) if (!prime[i]) { res.pb(i); for (LL j = i; a * i * j + i + j <= m; j++) prime[a * i * j + i + j] = 1; } }
const int N = 20000007; int a, n; bool vis[N], prime[N]; vector<int> res; void Inite(int m) { Rep(i, 1, m) if (!prime[i]) { res.pb(i); for (LL j = 1ll * a * i * i + 2 * i; j <= m; j += a * i + 1) prime[j] = 1; } } void Solve() { int d = (n - 1) / a; Inite(d); rep(i, 0, Size(res)) rep(j, i, Size(res)) { LL tp = 1ll * a * res[i] * res[j] + res[i] + res[j]; if (tp > d) break; vis[tp] = 1; } int cnt = 0; Rep(i, 1, d) if (vis[i]) cnt++; cout << cnt << endl; } int main() { cin >> a >> n; Solve(); return 0; }
E. 定向
题解:将无向图看作是有向图,又因为是无向图,所以添加的双向边在tarjan过程中只能用一条边且只经过一次(代码中的vis[ ]),然后跑一遍普通的tarjan算法就行了。如果只有一个强连通分量,且这个图是联通的,则存在方案。否则就impossible。
inline void upd(int &x, int y) { x < y && (x = y); } const int N = 1000005; int n, m, cnt, tot, block; int DFN[N], LOW[N], pa[N], head[N], ans[N]; bool use[N], vis[N]; stack<int> S; struct node { int to, next, id, dd; } e[2 * N]; void Inite() { block = tot = cnt = 0; mem(head, -1), mem(use, 0); } void addedge(int u, int v, int id, int dd) { e[tot].to = v, e[tot].id = id, e[tot].dd = dd, e[tot].next = head[u], head[u] = tot++; } void Tarjan(int u, int p) { pa[u] = p; DFN[u] = LOW[u] = ++cnt; use[u] = 1; S.push(u); for (int i = head[u]; ~i; i = e[i].next) if (e[i].to != p && !vis[e[i].dd]) { vis[e[i].dd] = 1; int v = e[i].to; ans[e[i].dd] = e[i].id; if (!DFN[v]) { Tarjan(v, u); LOW[u] = min(LOW[u], LOW[v]); } else if (use[v]) { LOW[u] = min(LOW[u], DFN[v]); } } if (DFN[u] == LOW[u]) { block++; while(S.top() != u) { use[S.top()] = 0; S.pop(); } use[u] = 0; S.pop(); } } void Solve() { Tarjan(1, 0); bool flag = 0; Rep(i, 1, n) if (!DFN[i]) { flag = 1; break; } if (flag || block != 1) { puts("impossible"); } else { Rep(i, 1, m) printf("%d", ans[i]); } } int main() { Inite(); sc(n), sc(m); Rep(i, 1, m) { int u, v; sc(u), sc(v); addedge(u, v, 1, i); addedge(v, u, 0, i); } Solve(); return 0; }
F. 青蛙
ps:关键点,青蛙过河的队形是一段连续的区间,考虑最左边的青蛙先跳,然后递推就行了。做题总抓不住关键点 ~