20201219 u,v,w
2021/5/2 18:29:14
本文主要是介绍20201219 u,v,w,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
开考前刚起床,所以一边考一边吃饭,然后整场都很迷。。。
A. u
考场
半天才搞懂“下三角区域”指哪个区域,手模样例确认后打了 \(O(qn^2)\) 的裸暴力,然后就不会做了。
看数据范围猜一下正解复杂度是 \(O(qlogn^2)\),开O2的话也许能卡过 \(O(qlog^2n)\),于是往线段树上想,后看到初始值为0,求最终矩阵的元素异或和,又开始想Trie树,30min后决定放弃。延续线段树的思路,把三角形拆到每一行,建 \(n\) 棵树状数组维护。大概10min就码完了。感觉的确和 hhy 在实中模拟赛时说的:“就像背课文一样”,于是失去了智力,写了树状数组单点修改、求区间最值都没想到差分(只有最后的一次询问。拆到行上差分可以做到 \(O(qn)\))。最后挂了对拍就没再管。
得分
期望:\(O(qnlogn)\) 47pts
实际:数据不保证三角形在矩阵范围内(但我的对拍保证了),RE到20pts
正解
二维差分。
用一个左上到右下的二维数组维护三角形要加的 \(s\),这样从 s[i][j]+=s[i-1][j-1]
就能推出每一列上要加的数,再从上到下递推就能解决Subtask5。剩下的部分容斥或开一个从左到右的差分数组消掉多加的 \(s\) 即可。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 2e3 + 1; int n,q; LL a[N][N],b[N][N]; LL c[N][N],ans; int main() { ios::sync_with_stdio(false);cin.tie(0); cin>>n>>q; while( q-- ) { int r,c,l,s; cin>>r>>c>>l>>s; a[r][c] += s, a[r+l][c+l] -= s; b[r+l][c] -= s, b[r+l][c+l] += s; } for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) a[i][j] += a[i-1][j-1], b[i][j] += b[i][j-1]; for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) c[i][j] = c[i-1][j] + a[i][j] + b[i][j], ans ^= c[i][j]; cout<<ans; return 0; }
B. v
考场
看到期望就头疼,更别提加上状压了。
直接开始写暴力。先枚举 \(x\) ,再状压dp出最优决策。
其实dp的写法比较接近正解,但时间复杂度似乎和暴力差不多。。。
Subtask3&4可以骗分。
得分
\(O(C_n^k2^n)\)
22pts
正解
大力深搜
需要吸氧。(这次给c++11和O2)
#include <cstdio> #include <map> using namespace std; #define RI register int const int MX = 1 << 25; int n,m; int st; double f[MX|1]; map<int,double> g; // 记忆化小数用int,大数map(卡常)。注意int数组大小 #define del(u,p) (((u>>1) & (~((1<<(p-1))-1))) | (u & ((1<<(p-1))-1))) /* O(1)删去u中第p位 u & ((1<<(p-1))-1)):取出前p-1位 ((u>>1) & (~((1<<(p-1))-1)):u>>1后取p位及以后 */ #define w(u,p) ((u & (1<<(p-1))) ? 1 : 0) // 计算u中第p为是否是白球 double dfs(int k, int u) { // 剩余操作k次,当前状态u if( !k ) return 0; if( u <= MX && f[u] != -1 ) return f[u]; if( g.find(u) != g.end() ) return g[u]; RI kk = n - (m - k); double res = 0; for(RI i = 1; i <= kk>>1; ++i) // 利用对称性剪掉一半的枝 res += max(dfs(k-1, del(u,i))+w(u,i), dfs(k-1, del(u,kk-i+1))+w(u,kk-i+1)) * 2; if( kk & 1 ) res += dfs(k-1, del(u,(kk>>1)+1)) + w(u,(kk>>1)+1); // for中无法计算kk为奇数时的中位数 res /= kk; if( u <= MX ) f[u] = res; else g[u] = res; return res; } int main() { scanf("%d%d",&n,&m); for(RI i = 0; i < n; ++i) { char ch = getchar(); while(ch!='W'&&ch!='B')ch=getchar(); if( ch == 'W' ) st |= 1<<i; } st |= 1<<n; /* int中高位0会被忽略,但本题中会造成记忆化出错。 如010和0010在int中一样,但本题中代表剩余球的状态不同。 因此在最高位的下一位补一个1,这样就变成了1010和10010。 */ for(RI i = 0; i <= MX; ++i) f[i] = -1; printf("%.9lf",dfs(m,st)); return 0; }
C. w
考场
一点思路都没有
但前两题双爆炸所以不想放弃这个题。想了近1h发现的性质,只有一个是有用的:每条边至多翻一次。先后想到了树剖、树上差分(然而并没有想起T1可差分)、树形dp。
最后还是写了骗分,链上的贪心没有写完。
正解
树形dp。状态比较新颖:除了以u为根的子树,还好保存u与fa连边的状态
由于以操作数、路径长度为关键字求最小,pair
就很方便。
操作数为所选路径的集合中,奇数度点的个数的一半。
#include <bits/stdc++.h> using namespace std; #define MP(x,y) make_pair(x,y) typedef pair<int,int> PII; const PII inf = MP(0x3f3f3f3f,0x3f3f3f3f); const int N = 1e5 + 1; PII operator+(PII a, PII b) { return MP(a.first+b.first,a.second+b.second); } int n,head[N],to[N<<1],w[N<<1],nxt[N<<1]; PII f[N][2]; // f[u][0/1]: u是否翻转到父亲的边,得到的奇数度的点的个数最小值,以及边的个数(路径长度和) inline void adde(int x, int y, int z, int mm) { to[mm] = y, w[mm] = z; nxt[mm] = head[x], head[x] = mm; } void dfs(int fa, int u, int op) { PII x = inf, y = MP(0,0); // x: u的儿子有一条翻到u; y: 没有 for(int i = head[u]; i; i = nxt[i]) { int v = to[i]; if( v == fa ) continue; dfs(u, v, w[i]); PII xx = min(x+f[v][0], y+f[v][1]), yy = min(x+f[v][1], y+f[v][0]); // 按定义更新x,y x = xx, y = yy; } if( op == 1 ) f[u][0] = inf; // 一定翻 else f[u][0] = min(MP(x.first+1,x.second),y); // u与儿子的一条连边翻则u为一个新的奇数度点 if( !op ) f[u][1] = inf; // 一定不翻 else f[u][1] = min(MP(x.first,x.second+1), MP(y.first+1,y.second+1)); // 从儿子伸过来:奇数度点数不变,路径长度+1 // 新开:操作数+1,路径长度+1 } int main() { scanf("%d",&n); for(int i = 1; i < n; ++i) { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); c = d==2 ? -1 : c^d; // -1/0/1:不管/不翻/翻 adde(a, b, c, i<<1), adde(b, a, c, i<<1|1); } dfs(0, 1, 2); printf("%d %d",f[1][0].first>>1,f[1][0].second); return 0; }
这篇关于20201219 u,v,w的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南