您的位置:首页 > 其它

ACdream群原创群赛(2) A~F J 解题报告

2012-11-12 16:50 148 查看
ACdream群)原创群赛(2)
地址为:http://www.acdream.net/contest.php?cid=1009



出题情况:
A~F 是我出的
G~I 旋风小晴天
J [CUGB] wwj
K nanae
先说一下情况:
貌似一开始大家被Board带歪了, F题我的题目比较坑爹是真的- -。。数学好的对数字敏感的同学上来扑肯定没错。。。我本来想的是应该会所有人先去搞晴天的G , 然后扑我的E 同时开 nanae 的K 。 这时候图论比较熟悉的同学应该已经开了J , 数论比较强的去搞HI。然后陆续会有人去搞B和C。最后过掉D就全体去扑A。这个流程还是比较科学的


A 题
Bella’s magic cube

题目类型:

矩阵乘法 + 手写栈模拟

解法:

此题看到题目有Q <= 10^5 首先就应该想到矩阵乘法。

建立 55 * 55 的矩阵,0~53号位置分别填写每个转化矩阵,在54号位置填写 1 作为改变某个地方值用。

考虑到如果循环用递归会爆栈的问题,故模拟递归,建立两个矩阵栈分别代表颜色和数字,如果进入循环则进栈,否则退栈。

需要注意的Trick是无时无刻出现的 /* 和 // 等组合。



B 题
Medicine

题目类型:

搜索

解法:

首先算出来所有数字的和, 然后判断是否有解。分k奇偶枚举公差之后,排序,就开始dfs搜索。

需要的剪枝——

1、 如果每一堆的最小项小于药片的最小项 false

2、 如果当前一堆枚举的和sum加上剩下药片的最小大于当前堆的容量 false

3、 如果当前堆正好放下一大块药片,放

4、 如果搜索到某一个药片,并且前一个药片已经搜索过+前一个药片和当前一个大小一样,跳过(重要剪枝)



C 题
The bomb war

题目类型:

简单hash + 二分(不是计算几何啊亲!!!!)

解法:

由于(我特别标明了啊。。原来100使用One hundred 写的!!)武器的数量小于100,那么考虑把X坐标hash。然后开100个vector放Y坐标。对于每一个robot,遍历X,二分查找第一个大于Robot[y]的Mine[y] 和小于的Mine[y] 。记录,删除。复杂度是log(n) 。数据结构的话,一个set和一个map就足以了。



D 题
Numbers in line

题目类型:

概率dp + 矩阵乘法 + 容斥原理

解法:

很容易能够想到转移矩阵DP[10* 10] (就是原来的矩阵)。对于一开始的概率向量{0.1,0.1….0.1} Start, 我们只需要算——概率向量End = Start * {E + DP + DP^2 +…+DP^(n - 1)}就可以算出最后一个数字的概率向量End。至于矩阵等比数列求和的方法请见POJ 3233

然后用容斥原理计算——每个数字至少出现一次的期望。即可。此题不卡精度



E 题
Mengzhu

题目类型:

数学 + 乱搞

解法:

利用精度 , 如果 A – B > 100 那么输出 A – 1 , 否则直接pow然后算



F 题
a + b

题目类型:

数学 或者 高精度

分析:

比较坑爹的是 Mod = 1e10 + 7 ,于是两个longlong 直接相乘再取模的话爆longlong~

解法1:

直接利用Java 高精度计算。不过每一步乘法需要都Mod一下

import java.math.*;
import java.io.*;
import java.util.*;

public class Main {
	public static void main(String[] args) throws Exception{
		Scanner cin = new Scanner(new FileReader("D:\\ACM\\出题\\20121111 Acdream 群赛\\Mengzhu's Math Problem\\input.txt"));
		PrintWriter pw = new PrintWriter("D:\\ACM\\出题\\20121111 Acdream 群赛\\Mengzhu's Math Problem\\output.txt");
		int re = cin.nextInt();
		for (int ri = 1; ri <= re; ++ri) {
			BigDecimal a = cin.nextBigDecimal();
			BigDecimal aa = a;
			BigDecimal b = cin.nextBigDecimal();
			if ( a.compareTo(b) < 0 ) {
				BigDecimal t = a; a = b; b = t;
			}
			BigDecimal d = a.subtract(b);
			if ( d.compareTo( BigDecimal.valueOf(1000) ) < 0 ) {
				//System.out.println(ri);
				double t = Math.pow(2.0, -d.doubleValue() ) + 1;
				t = Math.log(t) / Math.log(2);
				a = a.add(BigDecimal.valueOf(t));
			}
			a = a.subtract(BigDecimal.valueOf(1));
			a = a.setScale(9, RoundingMode.HALF_UP);
			if (a.subtract(aa).compareTo(BigDecimal.valueOf(2)) >0) System.out.println(ri);
			pw.println( a );	
		}
		pw.close();
	}
	//static Scanner cin = new Scanner(new BufferedInputStream(System.in));
}


解法2:

按位计算。以下是两个LongLong 相乘的代码

LL mul(LL a, LL b, LL c){
    LL r= 0;
    while(b){
        if(b&1) if((r+=a) >= c) r-=c;
        a<<=1;
        if(a>=c) a-=c;
        b>>=1;
    }
    return r;
}


J 题 I can't describe the problem [Author
: wwj]

题目类型:

图论

解法:

观察数据范围,点的个数和体力值都很小,那么可以开一个二维数组dis[i][j]代表到达i点剩余体力为j时的最短距离。然后就可以进行SPFA,状态的转移就两种,一种是走普通边,不需要花费体力,另外一种就是进行拆边。

拆边的方法其实也很简单。观察到边的大小只有10000,那么在刚开始我们就可以对1到10000直接二重循环枚举出所有的满足条件的a, b, c存起来。注意对每个值只保留最小是不对的。因为在魔法边上花费的体力是不跟边权成正比的。

当然还有更优的处理拆边的方法。因为这个条件是勾股数的条件。

而对于每组勾股数。均可以由以下方式构造

a=( m^ 2 - n ^ 2) * d, b = (2 * m * n) * d, c = (m ^ 2 + n ^ 2) * d

m> n > 0 , d > 0

其中m,n的奇偶性必须不同,并且gcd(m, n)= 1

令s = a + b + c

即s= 2 * m * (m + n) * d

s/ 2= m * (m + n) * d

其中(m+ n)必然是奇数

令k= m + n 则m < k < 2 * m

现在就是枚举s/2的因子。。注意上限是sqrt(s/2)向上取整 -1 因为 m < m+ n

然后令m等于枚举的因子后, (m + n)* d就算出来了

然后就枚举k满足m < k< 2 *m 并且k<= s/ 2 / m中的所有奇数了

然后就算出来了。



标称用的时间是600ms,如果刚开始用一个二重循环枚举10000以内满足要求的勾股数的话,用的时间会在2s+,不过题目给的时限是10s。

这道题其实挺直接的,绝对比ds出的那几道搜索好写。但是估计都被前面的题卡太久?就没多少人做这个题了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: