2017 Multi-University Training Contest
来源:互联网 发布:seo零基础 编辑:程序博客网 时间:2024/06/06 19:37
HDU - 6058 - Kanade's sum(双向链表)
题意:
求解,定义f(l,r,k)为[l,r]区间中第k大的元素。n为50w。k为80。
思路:
这题我们枚举每个元素i作为第k大出现的区间数量num,那么它对答案的贡献度就是i*num。
至于如果求解每个元素作为第k大出现的区间呢。我们思考如果找到这个元素i所在的位置。往左浮现出k个比他大的元素的位置,往右同理,如果定义元素i的位置是pos[0],那么往左的比他大的元素位置依次为pos[-1,-2,-3]。往右为正。那么[pos[k] + 1,pos[k - 1]] 和 [pos[0],pos[1] - 1]这个两个区间是不是随意组合都能截断出元素i作为第k大的区间,所以它的贡献值是左边这个区间的大小left乘上右边这个区间的大小。可以把这个一直往右挪动直到左边界达到元素i本来到的位置并且右边界达到极致为止。算k个乘积的加和,就能算出元素i作为第k大出现的区间数量num。如果我们用链表来维护这个数组,那么就可以做到O(1)的移动,那么对每个元素的查询的复杂度就是O(k*1)。
具体操作为:我们从小到大枚举元素,每次枚举出一个元素以后,找到它的区间们,删除这个元素。就能保证在链表中的每一个元素除了他本身,都大于我们要枚举的元素i。所以是O(1)的移动。这题就做完了。
哦对了!!!有个点要思考!!!为什么代码中右边界rb是要从lb往右跳k次,而不是直接使用元素i的位置。
答:是为了确保第一次枚举的时候,[lb,rb]中元素i的确为第k大。你问我为什么?emmm。万一你lb没跳够k次就到边界上了呢。
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int mod = 1e9 + 7;const int maxn = 5e5 + 5;int pre[maxn], nxt[maxn];int pos[maxn], a[maxn];int main(){ int T; scanf("%d", &T); while(T--) { int n, k; scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++) { pre[i] = i - 1; nxt[i] = i + 1; } pre[n + 1] = n; nxt[n + 1] = n + 1; pre[0] = 0; nxt[0] = 1; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); pos[a[i]] = i; } LL ans = 0; for(int i = 1; i <= n; i++) { int idx = pos[i]; int lb = idx; for(int j = 0; j < k; j++) lb = pre[lb]; int rb = lb; for(int j = 0; j < k; j++) rb = nxt[rb]; LL temp = 0; while(lb != idx && rb != n + 1) { temp += 1LL * (nxt[rb] - rb) * (nxt[lb] - lb); lb = nxt[lb], rb = nxt[rb]; } temp = temp * i; ans += temp; pre[nxt[idx]] = pre[idx]; nxt[pre[idx]] = nxt[idx]; } printf("%lld\n", ans); } return 0;}
HDU - 6060 - RXD and dividing(脑洞题)
题意:
就是把一棵树上除了标号为1以外的n-1个点,划分为k个点集合si(1<= i <= k),然后分别联通这k个点集合{}所需的路径的最小费用的加和。最大化这个和。问你要多少。
思路:
还真没想到。。比赛的时候。它的这个操作就是把n-1个点,每个点标记上1-k的标记,然后每条边的贡献度,就是min{这颗子树的大小,k}。加和就完了。dfs一次O(n)。
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 1e6 + 6;int n, k;int siz[maxn];vector<pair<int, int>>G[maxn];LL ans;void dfs(int u, int fa){ siz[u] = 1; for(auto o : G[u]) if(o.first != fa) { dfs(o.first, u); siz[u] += siz[o.first]; ans += 1LL * o.second * min(siz[o.first], k); }}int main(){ while(~scanf("%d%d", &n, &k)) { for(int i = 1; i <= n; i++) G[i].clear(); for(int i = 0; i < n - 1; i++) { int u, v, c; scanf("%d%d%d", &u, &v, &c); G[u].push_back({v, c}); G[v].push_back({u, c}); } ans = 0; dfs(1, -1); printf("%lld\n", ans); } return 0;}
HDU - 6061 - RXD and functions(NTT)
纯公式推导。然后就是套模板了。
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int mod = 998244353;const int maxn = 4e5+10;const int g = 3;LL qp[30];int getLen(int a){ a <<= 1; int res = 1; while(res < a) res <<= 1; return res;}//求余版本LL quickpow (LL a, LL b, LL Mod){a %= Mod;//至关重要! LL ret = 1; while(b) { if(b & 1) ret = ret * a % Mod; b >>= 1; a = (a * a) % Mod; } return ret;}void brc(LL *a, int l){ for(int i=1, j=l/2; i<l-1; i++) { if(i<j) swap(a[i],a[j]); int k=l/2; while(j>=k) { j-=k; k>>=1; } if(j<k) j+=k; }}void ntt(LL *y, int l, int on){ brc(y,l); int id = 0; long long u,t,tmp; for(int h=2;h<=l;h<<=1) { id++; for(int j=0;j<l;j+=h) { long long w = 1; for(int k=j;k<j+h/2;k++) { u = y[k]; t = w*y[k+h/2]%mod; y[k] = u+t; if(y[k]>=mod)y[k]-=mod; y[tmp=k+h/2]=u-t; if(y[tmp]<0)y[tmp]+=mod; w = w*qp[id]%mod; } } } if(on<0) { for(int i=1;i<l/2;i++)swap(y[i],y[l-i]); long long ni = quickpow(l,mod-2, mod); for(int i=0;i<l;i++)y[i] = (y[i]*ni)%mod; }}int c[maxn];LL fac[maxn], invf[maxn];LL F1[maxn], F2[maxn];void init(){ for(int i=0;i<21;i++) { int t=1<<i; qp[i]=quickpow(g,(mod-1)/t, mod); } fac[0] = 1; for(int i = 1; i <= 100000; i ++) { fac[i] = fac[i - 1] * i % mod; } invf[100000] = quickpow(fac[100000], mod - 2, mod); for(int i = 100000 - 1; i >= 0; i--) { invf[i] = invf[i + 1] * (i + 1) % mod; }}int main(){ init();// cout << invf[0] << endl; int n; while(~scanf("%d", &n)) { for(int i = 0; i <= n; i++) scanf("%d", &c[i]); int m; scanf("%d", &m); long long suma = 0; for(int i = 0; i < m; i++) { int x; scanf("%d", &x); suma -= x; suma = (suma + mod) % mod; } int len = getLen(n + 1); LL si = 1; for(int i = 0; i < len; i++) { if(i <= n) { F1[i] = 1LL * c[n - i] * fac[n - i] % mod; F2[i] = si * invf[i] % mod; si = si * suma % mod; } else F1[i] = F2[i] = 0; } ntt(F1, len, 1); ntt(F2, len, 1); for(int i = 0; i <len; i++) { F1[i] = F1[i] * F2[i] % mod; } ntt(F1, len, -1); for(int i = 0; i <= n; i++) { F1[i] = (F1[i] + mod) % mod; F1[i] = (F1[i] * invf[n - i] % mod); } for(int i = 0; i <= n; i++) { printf("%lld ", F1[n - i]); }puts(""); } return 0;}
HDU - 6063 - RXD and math(结论题 or 打表)
题意:
思路:
icpc赛场上血的教训就是,遇事不决先打表。一打表就出结论了。n^k,快速幂一下就AC了啊,这水的一笔。
emmm。什么情况,居然wa了。哦。n和k都是1e18,回顾一下快速幂quickpow(a, b, mod)的过程,a = a * a的操作直接溢出了。蠢比orz。
所以正解是,进入快速幂之前%一下n。
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int mod = 1e9 + 7;LL quickpow(LL a, LL b, LL Mod){ LL ret = 1; a %= Mod; while(b) { if(b & 1) ret = ret * a % Mod; b >>= 1; a = a * a % Mod; } return ret;}int main(){ LL n, k; for(int cas = 1; ~scanf("%lld%lld", &n, &k); cas++) { printf("Case #%d: %lld\n", cas, quickpow(n, k, mod)); } return 0;}
HDU - 6065 - RXD, tree and sequence(LCA+DP)
题意:
给你一棵树,编号1-n,根为1。给你一个序列a。问你,把这个序列a切成k段,每段的LCA加和最小为多少。
思路:
dp[i][j]:前i个数切割成j段,LCA最小值为多少。
思考一下转移,如果第i个数,自成一段那么应该是dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + depth[a[i]]).
如果第i个数并入之前一段,那么会有两种情况,一:第i个数字不影响第j段的LCA,那么dp[i][j] = min(dp[i][j], dp[i - 1][j]),二:第i个数字更新第j段的LCA,那么dp[i][j] = min(dp[i][j], dp[i - 2][j - 1] + depth[LCA(a[i -1], a[i])])。
解释一下第二种情况:设a[1] - a[n] 的LCA为L,那么易得,a[1] - a[n + 1]的LCA 就是 a[1] - a[n]中的任意一个和a[n + 1]的LCA。所以更新第j段的LCA的时候,我们采取
a[i - 1]和a[i]的LCA。然后还有是因为,处理出相邻点间lca深度之后,比如 7 4 5 6 3 9 10,若最优切分方式里 4 与 3 在不同区间里,4 与 3 之间的任何数,即 5 6,划分给 3 区间或者 4 区间,都不会影响最终答案。 所以可以这么做
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 3e5 + 10;const int inf = 0x3f3f3f3f;vector<int>G[maxn];const int root = 1;int pa[20][maxn];int depth[maxn];void dfs(int v, int fa, int d){ pa[0][v] = fa; depth[v] = d; for(auto o : G[v]) if(o != fa) dfs(o, v, d + 1);}void init(int V){ dfs(root, -1, 1); for(int k = 0; k + 1 < 20; k ++) { for(int v = 1; v <= V; v++) { if(pa[k][v] < 0) pa[k + 1][v] = -1; else pa[k + 1][v] = pa[k][pa[k][v]]; } }}int LCA(int u, int v){ if(depth[u] > depth[v]) swap(u, v); for(int k = 0; k < 20; k++) { if(depth[v] - depth[u] >> k & 1) v = pa[k][v]; } if(u == v) return u; for(int k = 20 - 1; k >= 0; k--) { if(pa[k][u] != pa[k][v]) { u = pa[k][u]; v = pa[k][v]; } } return pa[0][u];}int n, m;int a[maxn];vector<vector<int>>dp;int main(){ while(~scanf("%d%d", &n, &m)) { for(int i = 1; i <= n; i++) G[i].clear(); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } init(n); dp.resize(n + 1); for(int i = 0; i <= n; i++) { dp[i].resize(m + 1); for(int j = 1; j <= m; j++) dp[i][j] = inf; } dp[0][0] = 0; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { dp[i][j] = min(dp[i][j], dp[i - 1][j]); dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + depth[a[i]]); if(i > 1) dp[i][j] = min(dp[i][j], dp[i - 2][j - 1] + depth[LCA(a[i], a[i - 1])]); } } printf("%d\n", dp[n][m]); } return 0;}
HDU - 6066 - RXD's date(water)
思路:
说明我手速还可以啊。读了一会别的题,看榜上ac了,转过来读了直接秒的速度还挺快的 嘻嘻。
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int mod = 1e9 + 7;int main(){ int n; scanf("%d", &n); int cnt = 0; for(int i = 0; i < n; i++) { int x; scanf("%d", &x); if(x <= 35) cnt++; } printf("%d\n", cnt); return 0;}
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- #2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- #2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- Android进阶之路
- Tracking Area Update (TAU) procedure
- 01背包问题
- Myeclipse、eclipse安装lombok
- ORACLE startup报错之ORA-01154&&ORA-01155&&ORA-01033&&ORA-03113
- 2017 Multi-University Training Contest
- 【逐梦旅程Windows游戏编程学习笔记 ①】基本GDI绘图
- [HDU]6058 Kanade's sum
- Zookeeper
- 排序算法的时间复杂度和空间复杂度
- P2P中的NAT穿越方案简介
- 从日常开发说起,浅谈HTTP协议是做什么的
- js的image()循环创建,src始终为最近创建的那个解决办法(给image.onload传参)
- Javascript之Object.assign()