本场比赛由我、白翔、木连组成的iBeyond完成。
很水的一个比赛,没有特别难的算法,也没有特别难的题,做了8题,1题线段树、1题线段树优化DP、1题博弈、1题m叉哈夫曼树,其他4题都是模拟题。
A题 Anti-Goldbach's Conjecture 题目要求求2个函数,一个g(x)、一个sg(x)(x都为奇数),g(x)表示1<= i < x中,i为合数且它和另一个合数相加得x。只要算出x-2(因为x-2加上2为x不合法)之前奇数个数减去素数个数(2要特判),再累加起来算sg(x)。
C题 Collatz Conjecture 模拟题,题目要求的过程,一个数一个数的算经过的次数和经过的最大值,次数累加,最大值中取最大者输出即可。
D题 Data Encoding m叉哈夫曼树,求用m个字符表示长度为n的字符串的最小长度,题目看不太懂,到现在还没看懂,但看了样例以后发现是哈夫曼树,并且不是二叉的,那就是m叉的。求解时利用一个优先队列即可。但这题要特判,判断叶节点num % (n - 1) 是否等于 1 % (n - 1),如果不足,就用0补上知道满足为止,为什么这样呢?因为节点不足不处理的话,大的数却是在后面处理,这样最后算出来的长度最大。而那个等式,大家画一画m叉哈夫曼树就懂了。
E题 Echo 模拟题,第一行全部输出,第二行不熟第一个单词,第三行不熟第二个单词,以此类推。
F题 Flip the Bits 博弈题,给定一个超大的数,把它化成二进制数,可以把某个为1的i位翻为0,直到某个人没得翻的时候他就输了,但有一个前提,i翻的话每个它的因子都可以翻,正是这个规定让这题变得简单。先判断每一位单独翻的时候要走几步,可以用一个bool数组,true表示N点,false表示P点。最后输入n的时候,把2...n之间的N点上的值抑或起来,最后如果为true则为N点,false为P点。
G题 Girls and Boys 模拟题,刚看题目觉得是稳定婚姻匹配,然后各种YY,套用一个模版交上去华丽丽地Wa了,觉得男追女不妥,改成nv追男,但是天理不容,也Wa了。在Wa了几次之后仔细看了遍题目,发现在一起了后不能分手,这是多么悲剧啊,人的一生只有一个女朋友或男朋友,出题者的思想....其实思想和稳定婚姻匹配差不多,但这题要逆向而行,先匹配最不喜欢的人,有喜欢的再更新,这样就可以不分离了。
I题 Interview Arrangement 线段树优化DP。一开始觉得是贪心,如果每场考试价值一样的话就肯定是贪心,尽量多选择。但现实是残酷的,将每场时间按结束时间排序,并把每个时间离散化(因为n只有10万,那不一样的时间最多20万个,用map进行映射即可)。排完序之后明显就没有后效性了,最后的那场考试肯定是从他的开始时间之前的最大价值转移而来,而这之前的那个最大值又可以从开始之前的最大值转移而来。状态转移方程:dp[arr[i].end] = max(dp[i]) + arr[i].val;(i为大于arr[i].begin的时间,离散化之后范围为20万).如果这样暴力的花复杂度是O(n^2),拒绝暴力,求最大值,可以用线段树保存,每次更新的话单点更新,查询的花查询1--arr[i].begin内的最大值。总复杂度O(nlogn);
J题 Josephus Problem 线段树,约瑟夫环变形。说了这么多题,不多说了,贴个代码。
//C++ #include<iostream> #include<stdio.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int ans[100001]; int xw[100001]; const int maxn=200000; int w,sum[maxn<<2]; void build(int l,int r,int rt){///建立线段树 sum[rt] = r - l + 1; if(l == r) return ; int m = (l+r) >> 1; build(lson); build(rson); } int update(int p,int l,int r,int rt){///更新单个节点 sum[rt]--; if(l == r) return l ; int m = (l + r) >> 1; if(p <= sum[rt<<1]) return update(p,lson); else return update(p-sum[rt<<1],rson); } int main() { int n,m,i; int x,A,B,M; while(scanf("%d%d%d%d%d%d",&n,&m,&x,&A,&B,&M)!=EOF) { build(1,n,1); int z = 1; for(i = 1; i <= n; i++) { z = ((int)x+z)%sum[1]; if(z == 0) z = sum[1]; int s = update(z,1,n,1); ans[i] = s; x = (int)(((__int64)x * A + B) % M); } for(i = 0; i < m; i++) scanf("%d",&xw[i]); for(i=0;i<m-1;i++) printf("%d ",ans[xw[i]]); if(m!=0) printf("%d",ans[xw[m-1]]); printf("\n"); } return 0; }