近期总结_xdu 10月赛


XDU_OJ

10月赛

purple place

  思路比较简单,从0~99999枚举就可以,但是要注意到每一位的数字表示的是状态,是可以出现前导0的。

  所以输入时要用%s读取数据,枚举的数字转成string时注意些细节......

 

魔法喵点喵

 题目比较啰嗦,描述的是dp问题,造个3维数组dp[k][i][j],来表示第1个位置放k,第i个位置放j的最大值,同时预处理好每种j,前面能放的pre[j][]和后面能放的next[j][]就行了

转移方程: dp[k][i][j]=max{dp[k][i-1][t]+w[i][t])};  其中t是pre[j][]中的元素;由于要满足环状结构,最后一个位置根据倒数第2个和第1个特殊判断

 

彩云国的经济建设

 题意比较难懂,仔细理清楚,其实是个普通的统计问题,选择恰当的数据结构就能轻松解决,输入数据中岛的名字是string,注意处理好。

 

细胞分裂

 最小生成树模型,不知道为神马月赛的时候不停地wa,月赛完一提交就过了- -......,要注意的地方就是,并查集里最后合并节点x,y时,要合并它们的父亲fa[x]=fa[y];

 

弱弱的军事演习

 输入数据很多,充分体现了模块化的重要性。在这里首次意识到到排序算法选择的技巧,普通情况用自带的qsort函数就行了,而这里情况比较特殊,需要多次求前k项的和,而且元素数量很大,所以要用到另一种快速排序。

伪代码:

View Code
1 qick_sort(begin,end)
2 { 
3 int mid;
4    if(begin>end)return;//递归的边界,很重要
5    mid=part_sort(begin,end);//将元素分为>end和<end的2部分,返回end的位置mid
6 qick_sort(begin,mid-1);

7 qick_sort(mid+1,end);
8 }


这样递归到的区间与1~k无交集时就可以停止排序了,因为我们不关心1~k是否有序。

  由于题目的输出是针对原来的序列,所以要保证原序列seq不会受到排序的影响,可以用一个tmp临时存放。

神兽大黄

 第一行祭大黄 - -...吼吼~!!

 把小白吃的鸡腿当作放在另一个盒子里就行了。然后就可以套用组合数学的‘瓮中之球’公式,c(n-1,2*n-1),答案要求取模;n很大,求组合数时要用到 乘法逆元 这个技巧。

 之前不知道,特意查了一下这个知识点,网上不少是错误的;导论上‘线性模运算’一节有提到,要严谨地证明就牵扯到大量抽象代数的知识,这又是另一个领域了.....- -

 自己想到一个初等的解法,但适用性可能不那么广。

乘法逆元
  求组合数n特别大时,即使边乘边除也会溢出,而取模的运算中 (a/b)%p =(a%p)/(b%p) 不一定成立;怎么办呢?
 如果有  (a/b)%p ≡ k%p;
 我们只要找到那个k就好了;
 这是最自然地想法是写成方程的形式进行代数变换
 (a/b) = u + m*p;  (u为余数)    
 为了去掉分母同时乘以bx
 ax = u * bx + m*p*bx;
 再取模试试
 ax mod p = (u * bx) mod p + 0  (第二部分有因子P, 为0了)
 这时马上发现 只要 bx mod p = 1 我们就可以得到
 ax mod p = (u mod p) * (bx mod p) mod p= u;
 ax就是我们要找的那个k  ^ ^! 
 
 而bx ≡ 1 mod p,所以x就是乘法逆元(这是定义吧?)
 (尽量让过程严谨吧...推理有问题的地方希望有人指正- -)
  

(网上的解答是 (a/b)mod p = a*(1/b) mod p = (a mod p )* (1/b mod p) mod p 其中 1/b mod p 就是求b的乘法逆元,这么说很不严谨,1/b 不为整数,此时模p,很有乱搞的意味- -)

  最后 求b的乘法逆元用拓展欧几里得算法。

拓展欧几里得
 1 int x,y;
2 extculid(int a,int b)
3 {
4 int tmp;
5 if(b==0){x=1,y=0;return}
6 extculid(b,a%b);
7 tmp=x;
8 x=y;
9 y=tmp - a/b * y;
10 }
 
证明:
 ax+by = gcd(a,b); 其中a>b;
 b*x'+a%b*y'=gcd(b,a%b);
 gcd(a,b) = gcd(b,a%b)      (这就是‘拓展欧几里得’名字的来历)
 将 a%b= a - a/b * b;代入
 x=y';
 y=x'- a/b*y'
 递归边界是特殊解 b=0时gcd(a,b)=a; ->x=1,y=0;

 



 Let's SPFA 3

 

 无向图求最小圈。要是直接在邻接矩阵里查看对角线的值,必定wa死,因为无向图中1条边就是一个圈了 - -'

 

 正确的办法应该是设 u  k v 为最小圈中的3个点k为u->v最短路径上标号最大的点 则路径应该为 dist[u ->v](不经过k点的最短路)+ dist[v->k->u](经过k点的最短路)

 

   怎样求不经过k点的最短路呢?

 floyd算法里,迭代n次,每次相当于在u,v之间试图加入i节点,那么只要i在k之前,k就不会被加入u,v的最短路径,可以用一个3维数组来存每次迭代的结果

 d[k][i][j]为第k次迭代时i,j的最短距离 

 那么答案即为 d[0][i][k]+d[0][k][j]+d[k-1][i][j]的最小值(k<n &&k!=i&&k!=j&&i!=j)

 到这里可能还存在问题,i,j的最短路径中只考虑了标号为k-1之前的节点,这个答案是否太片面呢?

 将圈中的节点,按标号从小到大排序v1,v2.....i,j,k  长度为d[k-1][v1][j]+d[0][j][k]+d[0][k][v1];

 因为枚举了k,i,j,所以上述情况不会被遗漏,同一个最小圈会有很多表示方式,只要枚举到了一个就行了。

 

你可能感兴趣的:(总结)