2015 Multi-University Training Contest 1
2016-07-26 19:13
381 查看
感觉题目很棒,贴上留作记录。
A
定义 f(L,R)为区间[L,R]里面合法数的个数。一个数a[i]合法意味着L <= i <= R且区间里面不存在j使得i!=j&& a[i]%a[j]==0。
题意:问你所有区间合法数的总数。
思路:一开始一直YYO(n)的神算法,发现实在不可搞,最后直接暴力找每个数的最近因子区间就过了。
B
题意:问有多少个区间的最大值-最小值< k。
RMQ + 二分就好了。
F
题意:给定一棵树和m条链以及每条链的价值,你需要选若干条点不相交的链使得这些链的价值总和最大。
思路:dp[i]表示以i节点为根的子树可以得到的最大价值,sum[i]=∑dp[j] 其中j是i的孩子。
有两种决策:
一、i节点不选链或者不在链上,那样直接就是dp[i]=sum[i];
二、i节点为某条链k的lca,那样dp[i]=v[k]+∑sum[j]−∑dp[j] 其中j是k链上的点。
预处理LCA,用树链剖分维护就可以啦。
G
题意:问你最少需要去掉多少条边可以截断1 - n的最短路以及最多去掉多少条边最短路依然存在。
思路:就是一个最小割 + 边数最少的最短路。
J
题意:去掉2,3,4,5,6,7,…的r次方其中2 <= r <= 63得到Y序列。问你Y序列里面第n个数是多少。
思路:先容斥,发现可以很快得到前n个数里面去掉多少个数。这样我们可以直接二分,但是二分会T,那就用迭代了。
A
定义 f(L,R)为区间[L,R]里面合法数的个数。一个数a[i]合法意味着L <= i <= R且区间里面不存在j使得i!=j&& a[i]%a[j]==0。
题意:问你所有区间合法数的总数。
思路:一开始一直YYO(n)的神算法,发现实在不可搞,最后直接暴力找每个数的最近因子区间就过了。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> using namespace std; typedef long long LL; const int MAXN = 1e5 + 10; const int MOD = 1e9 + 7; int a[MAXN], cnt[MAXN]; vector<int> G[MAXN], P[MAXN]; void Solve(int n) { for(int i = 1; i * i <= n; i++) { if(n % i == 0) { P .push_back(i); if(i * i != n) { P .push_back(n / i); } } } } int main() { for(int i = 1; i <= 10000; i++) { P[i].clear(); Solve(i); } int n; while(scanf("%d", &n) != EOF) { for(int i = 1; i <= 10000; i++) G[i].clear(), cnt[i] = 0; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); G[a[i]].push_back(i); cnt[a[i]]++; } LL ans = 0; for(int i = 1; i <= 10000; i++) { for(int j = 0; j < cnt[i]; j++) { int p1 = G[i][j]; int l = 0, r = n + 1; for(int x = 0; x < P[i].size(); x++) { int v = P[i][x]; for(int y = 0; y < cnt[v]; y++) { int p2 = G[v][y]; if(p2 < p1) { l = max(p2, l); } else if(p2 > p1) { r = min(p2, r); } } } l++; r--; ans = (ans + 1LL * (r - p1) * (p1 - l) + (r - p1) + (p1 - l)) % MOD; //cout << ans << endl; } } ans += n; ans %= MOD; printf("%lld\n", ans); } return 0; }
B
题意:问有多少个区间的最大值-最小值< k。
RMQ + 二分就好了。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #include <cmath> #define CLR(a, b) memset(a, (b), sizeof(a)) #define ll o<<1 #define rr o<<1|1 using namespace std; typedef long long LL; const int MAXN = 1e5 + 10; const int MAXM = 1e6 + 10; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; int a[MAXN]; int dp[2][MAXN][20]; void RMQ_init(int n) { for(int i = 1; i <= n; i++) { dp[0][i][0] = dp[1][i][0] = a[i]; } for(int j = 1; (1 << j) <= n; j++) { for(int i = 1; i + (1 << j) - 1 <= n; i++) { dp[0][i][j] = max(dp[0][i][j-1], dp[0][i + (1 << (j - 1))][j-1]); dp[1][i][j] = min(dp[1][i][j-1], dp[1][i + (1 << (j - 1))][j-1]); } } } int Query(int L, int R, int op) { int k = 0; while((1 << (k + 1) <= R - L + 1)) k++; return op == 0 ? max(dp[0][L][k], dp[0][R - (1 << k) + 1][k]) : min(dp[1][L][k], dp[1][R - (1 << k) + 1][k]); } int main() { int t; scanf("%d", &t); while(t--) { int n, k; scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } RMQ_init(n); LL ans = 0; for(int i = 1; i <= n; i++) { int l = i, r = n, pos; while(r >= l) { int mid = l + r >> 1; if(Query(i, mid, 0) - Query(i, mid, 1) < k) { pos = mid; l = mid + 1; } else { r = mid - 1; } } ans += pos - i + 1; } printf("%lld\n", ans); } return 0; }
F
题意:给定一棵树和m条链以及每条链的价值,你需要选若干条点不相交的链使得这些链的价值总和最大。
思路:dp[i]表示以i节点为根的子树可以得到的最大价值,sum[i]=∑dp[j] 其中j是i的孩子。
有两种决策:
一、i节点不选链或者不在链上,那样直接就是dp[i]=sum[i];
二、i节点为某条链k的lca,那样dp[i]=v[k]+∑sum[j]−∑dp[j] 其中j是k链上的点。
预处理LCA,用树链剖分维护就可以啦。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #define CLR(a, b) memset(a, (b), sizeof(a)) #define ll o<<1 #define rr o<<1|1 using namespace std; typedef long long LL; const int MAXN = 1e5 + 10; const int MAXM = 1e6 + 10; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; struct Edge { int from, to, next; }; Edge edge[MAXN<<1]; int head[MAXN], edgenum; int vs[MAXN<<1]; int depth[MAXN<<1]; int id[MAXN]; int dfs_clock; void init() { CLR(head, -1); edgenum = 0; } void addEdge(int u, int v) { Edge E = {u, v, head[u]}; edge[edgenum] = E; head[u] = edgenum++; } void DFS(int u, int fa, int d) { id[u] = dfs_clock; vs[dfs_clock] = u; depth[dfs_clock++] = d; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == fa) continue; DFS(v, u, d + 1); vs[dfs_clock] = u; depth[dfs_clock++] = d; } } void find_depth() { dfs_clock = 1; CLR(vs, 0); CLR(id, 0); CLR(depth, 0); DFS(1, -1, 0); } int dp[MAXN<<1][30]; void RMQ_init(int NN) { for(int i = 1; i <= NN; i++) dp[i][0] = i; for(int j = 1; (1<<j) <= NN; j++) { for(int i = 1; i + (1<<j) - 1 <= NN; i++) { int a = dp[i][j-1]; int b = dp[i + (1<<(j-1))][j-1]; if(depth[a] < depth[b]) dp[i][j] = a; else dp[i][j] = b; } } } int query(int L, int R) { int k = 0; while((1<<(k+1)) <= R - L + 1) k++; int a = dp[L][k], b = dp[R - (1 << k) + 1][k]; if(depth[a] < depth[b]) return a; else return b; } int LCA(int u, int v) { int x = id[u], y = id[v]; if(x > y) return vs[query(y, x)]; else return vs[query(x, y)]; } int chain[MAXN][4]; vector<int> G[MAXN]; struct Tree { int l, r, sum1, sum2; }; Tree tree[MAXN<<2]; void PushUp(int o, int op) { if(op == 1) { tree[o].sum1 = tree[ll].sum1 + tree[rr].sum1; } else { tree[o].sum2 = tree[ll].sum2 + tree[rr].sum2; } } void Build(int o, int l, int r) { tree[o].l = l; tree[o].r = r; tree[o].sum1 = tree[o].sum2 = 0; if(l == r) { return ; } int mid = (l + r) >> 1; Build(ll, l, mid); Build(rr, mid+1, r); } void Update(int o, int pos, int v, int op) { if(tree[o].l == tree[o].r) { if(op == 1) { tree[o].sum1 = v; } else { tree[o].sum2 = v; } return ; } int mid = (tree[o].l + tree[o].r) >> 1; if(pos <= mid) Update(ll, pos, v, op); else Update(rr, pos, v, op); PushUp(o, op); } int Query(int o, int L, int R, int op) { if(tree[o].l == L && tree[o].r == R) { return op == 1 ? tree[o].sum1 : tree[o].sum2; } int mid = (tree[o].l + tree[o].r) >> 1; if(R <= mid) return Query(ll, L, R, op); else if(L > mid) return Query(rr, L, R, op); else { return Query(ll, L, mid, op) + Query(rr, mid+1, R, op); } } int son[MAXN], num[MAXN]; int top[MAXN], pos[MAXN], Id; int dep[MAXN], pre[MAXN]; void DFS1(int u, int fa, int d) { dep[u] = d; pre[u] = fa; num[u] = 1; son[u] = -1; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == fa) continue; DFS1(v, u, d+1); num[u] += num[v]; if(son[u] == -1 || num[son[u]] < num[v]) son[u] = v; } } void DFS2(int u, int T) { top[u] = T; pos[u] = ++Id; if(son[u] == -1) return ; DFS2(son[u], T); for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == pre[u] || v == son[u]) continue; DFS2(v, v); } } int GetSum(int u, int v, int op) { int f1 = top[u], f2 = top[v]; int ans = 0; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(u, v); swap(f1, f2); } ans += Query(1, pos[f1], pos[u], op); u = pre[f1], f1 = top[u]; } if(dep[u] > dep[v]) swap(u, v); ans += Query(1, pos[u], pos[v], op); return ans; } int d[MAXN], s[MAXN]; void Solve(int u, int fa) { s[u] = 0; d[u] = 0; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == fa) continue; Solve(v, u); s[u] += d[v]; } Update(1, pos[u], s[u], 1); d[u] = s[u]; for(int j = 0; j < G[u].size(); j++) { int k = G[u][j]; d[u] = max(d[u], chain[k][2] + GetSum(chain[k][0], chain[k][1], 1) - GetSum(chain[k][0], chain[k][1], 2)); } Update(1, pos[u], d[u], 2); } int main() { int t; scanf("%d", &t); while(t--) { int n, m; scanf("%d%d", &n, &m); init(); for(int i = 0; i < n-1; i++) { int u, v; scanf("%d%d", &u, &v); addEdge(u, v); addEdge(v, u); } DFS1(1, -1, 1); Id = 0; DFS2(1, 1); Build(1, 1, Id); for(int i = 1; i <= n; i++) G[i].clear(); find_depth(); RMQ_init(dfs_clock - 1); for(int i = 0; i < m; i++) { scanf("%d%d%d", &chain[i][0], &chain[i][1], &chain[i][2]); chain[i][3] = LCA(chain[i][0], chain[i][1]); G[chain[i][3]].push_back(i); } Solve(1, -1); printf("%d\n", d[1]); } return 0; }
G
题意:问你最少需要去掉多少条边可以截断1 - n的最短路以及最多去掉多少条边最短路依然存在。
思路:就是一个最小割 + 边数最少的最短路。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #define CLR(a, b) memset(a, (b), sizeof(a)) using namespace std; typedef long long LL; const int MAXN = 2 * 1e3 + 10; const int MAXM = 1e6 + 10; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; struct Edge{ int from, to, cap, flow, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; void init() {CLR(head, -1); edgenum = 0;} void addEdge(int u, int v, int w) { Edge E1 = {u, v, w, 0, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } bool vis[MAXN]; int dist[MAXN], cur[MAXN]; bool Bfs(int s, int t) { queue<int> Q; Q.push(s); CLR(vis, false); CLR(dist, -1); vis[s] = true; dist[0] = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(!vis[E.to] && E.cap > E.flow) { dist[E.to] = dist[u] + 1; if(E.to == t) return true; vis[E.to] = true; Q.push(E.to); } } } return false; } int DFS(int x, int a, int t) { if(x == t || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = edge[i].next) { Edge &E = edge[i]; if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(E.cap-E.flow, a), t)) > 0) { edge[i].flow += f; edge[i^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int s, int t) { int flow = 0; while(Bfs(s, t)) { memcpy(cur, head, sizeof(head)); flow += DFS(s, INF, t); } return flow; } struct Edge2 { int from, to, val, next; }; Edge2 edge2[MAXM]; int head2[MAXN], edgenum2; void addEdge2(int u, int v, int w) { Edge2 E1 = {u, v, w, head2[u]}; edge2[edgenum2] = E1; head2[u] = edgenum2++; } int num[MAXN]; void SPFA(int s, int t) { CLR(vis, false); CLR(dist, INF); CLR(num, INF); queue<int> Q; Q.push(s); vis[s] = true; dist[s] = 0; num[s] = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = false; for(int i = head2[u]; i != -1; i = edge2[i].next) { Edge2 E = edge2[i]; if(dist[E.to] > dist[u] + E.val) { dist[E.to] = dist[u] + E.val; num[E.to] = num[u] + 1; if(!vis[E.to]) { vis[E.to] = true; Q.push(E.to); } } else if(dist[E.to] == dist[u] + E.val) { num[E.to] = min(num[E.to], num[u] + 1); } } } } int main() { int n, m; while(scanf("%d%d", &n, &m) != EOF) { CLR(head2, -1); edgenum2 = 0; for(int i = 0; i < m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); addEdge2(u, v, w); addEdge2(v, u, w); } SPFA(1, n); init(); for(int i = 1; i <= n; i++) { for(int j = head2[i]; j != -1; j = edge2[j].next) { int v = edge2[j].to; if(dist[v] == dist[i] + edge2[j].val) { addEdge(i, v, 1); } } } printf("%d %d\n", Maxflow(1, n), m - num ); } return 0; }
J
题意:去掉2,3,4,5,6,7,…的r次方其中2 <= r <= 63得到Y序列。问你Y序列里面第n个数是多少。
思路:先容斥,发现可以很快得到前n个数里面去掉多少个数。这样我们可以直接二分,但是二分会T,那就用迭代了。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #include <cmath> #define CLR(a, b) memset(a, (b), sizeof(a)) #define ll o<<1 #define rr o<<1|1 using namespace std; typedef long long LL; const int MAXN = 1e5 + 10; const int MAXM = 1e6 + 10; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; bool vis[80]; void getp() { for(int i = 2; i <= 70; i++) { if(vis[i]) continue; for(int j = 2 * i; j <= 70; j += i) { vis[j] = true; } } } int p[30], k; int q[1000000], top; LL Count(LL n) { LL ans = n; for(int i = 1; i < top; i++) { LL res = (LL)pow(n + 0.5, 1.0 / abs(q[i])) - 1; ans += q[i] / abs(q[i]) * res; } return ans - 1; } int main() { getp(); int t; scanf("%d", &t); while(t--) { LL n; int m; scanf("%lld%d", &n, &m); k = 0; for(int i = 2; i <= m; i++) { if(!vis[i]) { p[k++] = i; } } top = 0; q[top++] = 1; for(int i = 0; i < k; i++) { int T = top; for(int j = 0; j < T; j++) { q[top++] = q[j] * p[i] * (-1); if(abs(q[top-1]) > 62) { top--; } } } LL ans = n; while(1) { LL num = Count(ans); if (num == n) break; ans += n - num; } printf("%lld\n", ans); } return 0; }
相关文章推荐
- 2016 Multi-University Training Contest 3 hdu 5762 Teacher Bo【计算几何】
- [LeetCode]172. Factorial Trailing Zeroes
- 2016 Multi-University Training Contest 3 hdu 5753 Permutation Bo【打表+递推】
- MAT分析器中的shallow and retained heap详解
- 2016 Multi-University Training Contest 3 hdu 5752 Sqrt Bo【思维】
- SORT
- 我与IDEA的不舍情缘
- 2016 Multi-University Training Contest 3-1011.Teacher Bo,暴力!
- Communications link failure的解决办法
- Dialog CTS fail-DialogTest.testSetDismissMessage fail原因和解决办法
- hdu 5752 Sqrt Bo(2016 Multi-University Training Contest 3——水题)
- OnPaint和OnDraw的区别
- 11gR2 Grid infrastructure fails to install
- grails与ajax书写
- zhishangbuzaixianxilie
- 有限状态机&Time_wait的解读
- Incorrect key file for table './xx_db/xx_table.MYI'; try to repair it
- perl:warning:Setting locale failed解决办法
- HDU-2016 Multi-University Training Contest 3-Sqrt Bo-大数开方
- rails production secret_key的设置