[swust]Fighting for 2017 season contest 8 快速幂,简单DP,暴力or指针交换,树上背包,线段树区间开根
2017-03-12 16:33
591 查看
题目地址:https://oj.splayx.com/vjudge/contest/view.action?cid=4#problem/A
A:水题,一个快速幂搞定。
B:显然应该是一个DP。状态表示为 dp[i][0]表示第i天,我们能换得最多的马克,dp[i][1]表示第i天,我们能换得最多的美元。然后转移就非常简单了。
就是美元和马克的相互变换,计算对应的答案。
C:行列的交换可以用指示行列的指针来间接交换,或者由于数据水直接暴力也可过。
D,相当于树上的分组背包问题。只不过这里没有组里只能取一个的限制,而是可以取多个。我们考虑dp[i][j]表示第i门课程,包括其自身在内选j门子课程的最大收益。那么对于节点i转移比较简单应该是dp[i][j]=max(dp[i][j], dp[i][j-k]+dp[(i的子结点v)][k] k∈[0,j) (不能取k=j,因为至少有一门是先修课v) j倒序循环(分组背包思想)
E,线段树区间开根,考虑一个1e12的数,不超过10次可以开到1,所以我们打个lazy标记就可以很快把一个线段缩成一个点,线段树经典套路了。注意l有可能小于r。
A:水题,一个快速幂搞定。
//tvoj 1116 #include <bits/stdc++.h> using namespace std; const int mod = 7; int powmod(int a, int b){ int res = 1; while(b){ if(b&1) res = res*a%mod; a = a*a%mod; b>>=1; } return res; } int main() { int n; while(scanf("%d", &n) != EOF) { int ans = 0; for(int i = 1; i <= n; i++){ int x = powmod(2, i); int y = ((i%7)*(i%7))%7; if((x-y+7)%7==0) ans++; } printf("%d\n", ans); } return 0; }
B:显然应该是一个DP。状态表示为 dp[i][0]表示第i天,我们能换得最多的马克,dp[i][1]表示第i天,我们能换得最多的美元。然后转移就非常简单了。
dp[i][0] = max(dp[i-1][0], dp[i-1][1]*(double)a[i]/100.0); dp[i][1] = max(dp[i-1][1], dp[i-1][0]/(double)(a[i])*100.0);
就是美元和马克的相互变换,计算对应的答案。
//tyvj 1095 #include <bits/stdc++.h> using namespace std; int n, a[105]; double dp[105][2]; //dp[i][0]表示第i天,我们能换得最多的马克,dp[i][1]表示第i天,我们能换得最多的美元 int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); dp[1][0] = a[1]; dp[1][1] = 100; for(int i = 2; i <= n; i++){ dp[i][0] = max(dp[i-1][0], dp[i-1][1]*(double)a[i]/100.0); dp[i][1] = max(dp[i-1][1], dp[i-1][0]/(double)(a[i])*100.0); } printf("%.2f\n", dp [1]); }
C:行列的交换可以用指示行列的指针来间接交换,或者由于数据水直接暴力也可过。
//tyvj 2012 #include <bits/stdc++.h> using namespace std; int a[710][710], row[710], col[710]; int main() { int n, k; scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++){ for(int j = 1; j <= n; j++){ scanf("%d", &a[i][j]); } } for(int i = 1; i <= n; i++) row[i] = i, col[i] = i; while(k--){ char op[10]; int x, y; scanf("%s%d%d", op, &x, &y); if(op[0] == 'R'){ swap(row[x], row[y]); } else if(op[0] == 'C'){ swap(col[x], col[y]); } else{ printf("%d\n", a[row[x]][col[y]]); } } }
D,相当于树上的分组背包问题。只不过这里没有组里只能取一个的限制,而是可以取多个。我们考虑dp[i][j]表示第i门课程,包括其自身在内选j门子课程的最大收益。那么对于节点i转移比较简单应该是dp[i][j]=max(dp[i][j], dp[i][j-k]+dp[(i的子结点v)][k] k∈[0,j) (不能取k=j,因为至少有一门是先修课v) j倒序循环(分组背包思想)
//tyvj 1051 #include <bits/stdc++.h> using namespace std; const int maxn = 410*410; int n, m, edgecnt, head[410]; int dp[410][410], score[410]; struct edge{ int v, nxt; edge(){} edge(int v, int nxt):v(v), nxt(nxt){} }E[maxn]; void init(){ edgecnt = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v){ E[edgecnt].v = u, E[edgecnt].nxt = head[v], head[v] = edgecnt++; } void dfs(int x){ dp[x][1] = score[x]; for(int i = 2; i <= m; i++) dp[x][i] = 0; for(int i = head[x]; ~i; i = E[i].nxt){ int v = E[i].v; dfs(v); for(int j = m; j; j--){ for(int k = 0; k < j; k++){ dp[x][j] = max(dp[x][j], dp[x][j-k]+dp[v][k]); } } } } int main(){ init(); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++){ int u; scanf("%d%d", &u, &score[i]); addedge(i, u); } m++; dfs(0); printf("%d\n", dp[0][m]); return 0; }
E,线段树区间开根,考虑一个1e12的数,不超过10次可以开到1,所以我们打个lazy标记就可以很快把一个线段缩成一个点,线段树经典套路了。注意l有可能小于r。
//tyvj 1941 #include <bits/stdc++.h> using namespace std; const int maxn = 100010; #define lson l,m,o*2 #define rson m+1,r,o*2+1 namespace segementtree{ int c[maxn*4]; long long sum[maxn*4]; void pushup(int o){ sum[o] = sum[o*2]+sum[o*2+1]; c[o] = c[o*2] || c[o*2+1] ? 1 : 0; } void build(int l, int r, int o) { if(l == r){ scanf("%lld", &sum[o]); c[o] = sum[o]>1?1:0; return; } int m = (l+r)/2; build(lson); build(rson); pushup(o); } void update(int L, int R, int l, int r, int o){ if(!c[o]) return; if(l == r){ sum[o] = sqrt(sum[o]); if(sum[o]<=1) c[o]=0; return; } int m=(l+r)/2; if(L<=m&&c[o*2]) update(L, R, lson); if(m<R&&c[o*2+1]) update(L, R, rson); pushup(o); } long long query(int L,int R, int l, int r, int o){ if(L<=l&&r<=R) return sum[o]; int m=(l+r)/2; if(R<=m) return query(L, R, lson); else if(L>m) return query(L,R, rson); else{ return query(L,m,lson)+query(m+1,R,rson); } } } using namespace segementtree; int main() { int n, m; scanf("%d", &n); build(1, n, 1); scanf("%d", &m); for(int i = 1; i <= m; i++){ int cmd, l, r; scanf("%d%d%d", &cmd, &l, &r); if(l>r) swap(l, r); if(cmd == 1) printf("%lld\n", query(l, r, 1, n, 1)); else update(l, r, 1, n, 1); } return 0; }
相关文章推荐
- [swust]Fighting for the 2017 season contest 7 雀巢原理,并查集,离线BIT,中位数,前缀和,贪心,背包DP
- Fighting For 2017 Season Contest 1 题解
- 2016-2017 ACM-ICPC East Central North America Regional Contest (ECNA 2016) F 区间dp
- WHU B Color 2017 Wuhan University Programming Contest 一道简单树形dp
- HDU 6039 Gear up 2017 Multi-University Training Contest - Team 1 线段树维护到树根距离 区间修改 区间最值
- 【HDU5745 2016 Multi-University Training Contest 2L】【bitset做法or暴力】La Vie en rose 目标串多少子串可以被原始串做相邻交换得到
- 2017 Wuhan University Programming Contest (Online Round) D. Events,线段树区间更新+最值查询!
- [树上依赖多重背包 DP] BZOJ 4910 [Sdoi2017]苹果树
- POJ 2182 Lost Cows 题解 (线段树维护区间变化or暴力)
- POJ 1436——Horizontally Visible Segments(线段树,区间染色+暴力+简单hash)
- Codeforces 730 J. Bottles DP 0-1背包- 2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest
- “盛大游戏杯”第15届上海大学程序设计联赛夏季赛暨上海高校金马五校赛题解&&源码【A,水,B,水,C,水,D,快速幂,E,优先队列,F,暴力,G,贪心+排序,H,STL乱搞,I,尼姆博弈,J,差分dp,K,二分+排序,L,矩阵快速幂,M,线段树区间更新+Lazy思想,N,超级快速幂+扩展欧里几德,O,BFS】
- hdu1166(简单线段树应用,求区间和)
- ZOJ 3682 简单dp 背包
- HDU 3698 Let the light guide us 线段树求区间优化dp
- [USACO 2.3.4]货币系统【DP完全背包的简单应用】CSUST 1081
- [USACO 2.3.4]货币系统【DP完全背包的简单应用】CSUST 1081
- 简单01背包 POJ3211 Washing Clothes 多种衣服分别dp
- poj 3468 A Simple Problem with Integers(线段树区间更新 or 树状数组区间更新)
- 线段树求区间最大值和最小值(指针)