2010年下半年每周集训之组队常规训练1解题报告

2010年下半年每周集训之组队常规训练1-by zhendeluzi

A) Flip Game

 

我们把b、w看作0和1,于是题意就是说给出一个4x4的01矩阵,然后可以进行0、1互相转换的操作(0变1,1变0)

 

显然我们有:
1 ^ 1 = 0;
0 ^ 1 = 1;

 

然后我们用一个16位的数字来表示状态(4 * 4 == 16),预处理出来对每个点翻转所会影响到的位(共16种),于是状态转移就变得很简单了:

 

int tranMatrix[16] = {...}; // 状态转移矩阵
int curState = first element in queue; // 当前状态

 

for (int i = 0; i != 16; ++i) {
  int newState; // 新状态

 

  newState = curState ^ tranMatrix[i];
  if (newState is not in queue) {
    push newState into queue;
  }
}

 

题目中没有说究竟有多少组样例,如果样例数较少(比如说只有10组),每次直接搜索就可以了,如果说样例较多,则一开始从全黑和全白状态搜出来到达所有(可能到达的)状态所需要的步数,在服务器上打表,然后读入数据后直接查表即可。


时间复杂度 = O(2 ^ (n ^ 2)),考虑到 n == 4,复杂度可以接受。

 

B) Ugly Numbers

 

在服务器上直接按照要求把小于一个足够大的数字K的Ugly Numbers打到一个表里面就行了,K可以预先在本地跑一下试试,500W应该是足够了。
考虑到产生Ugly Numbers时可能出现重复的数字,用一个map判重。
然后对于每次输入直接查表即可。


时间复杂度 = O(KlogK)

 

C) 食物链

 

..... = = baiyuang讲吧。。数据结构我不擅长的说。。
时间复杂度 = O(???)

baiyuang的解题报告:/acmhome/solutionReportList.do?&method=solutionReportDetail&id=15

 

D) Count the number of Soldiers

 

结果 = M * N + L


时间复杂度 = O(1)

 

E) Derivative

 

定义一个结构体 Term:

 

struct Term {
  int a;
  int b;
}

 

来表示a * b ^ x。求导过程就是a *= b--;

 

麻烦的主要是模拟。
对于读系数的话,可以直接用sscanf(s, "%d", &a)这样读,sscanf对于+1这种也能处理。

 

时间复杂度 = O(???)

 

F) Dragon Ball Kai

 

定义一个布尔变量 f,发生 exchange 就给 f 取反。发生 which 的时候如果 f 是 false 就输出 NO,否则输出 YES。

 

时间复杂度 = O(n)

 

G) Happy Numbers

 

从1到500W分别判定一下是不是Happy Number,如果是的话那么a[x] = true,否则a[x] = false。
判定的时候显然是一个递归过程,需要注意到的是可能会出现环(出现环就不是Happy Number了,否则最终一定会(至少对于前500W来说)收敛到1。
递归的时候可以加上一个记忆化,因为搜索过程整体上来说是不断递减的(不过不是严格递减的,所以如果递推的话顺序很难确定),因此子状态会重叠,加上记忆化可以加速。

 

然后我们把 a 数组看作是一个只有 1(true)、0(false)的数组,对于前K个元素里面有多少个1,就是有多少个Happy Number。这儿可以用sum[i] = sum[i - 1] + a[i]直接求出来 a 数组的前缀和。

 

时间复杂度 = O(n)

 

H) Remove Numbers

 

首先,我们用012345678这样的字符串来描述状态,记录的时候会发现这样的字符串刚好可以用康托展开的方法来压缩状态(状态数 = 9!)。
状态转移的时候可以先预处理一个转移矩阵(根据空格所在位置不同有9种转移方式――如果在最中间那个空格,则可以转移到周围8个的任意一个,否则只能转移到前后相邻的两个空格和中间那个空格),这样会降低编码复杂度(类似于A题,在这一点上我觉得A H两题有点重复)。
同时考虑到最多有50组样例,因此可以先反向求出来每个状态到最终状态所需要的步数(求的时候是求最终状态到每个状态的步数,考虑到正反向的代价是一样的,所以这样求出来也就是每个状态到最终状态的步数)并在服务器上打表。
但是考虑到1不能移动,因此1有8种位置,所以针对1位置的不同,反向求解8次。
最后对每组样例直接查表即可。

 

时间复杂度 = O(n * n!),考虑到n == 9,复杂度可以接受。

 

I) Weight

 

首先,如果 n 是 2 ^ K - 1,那么显然切K - 1次最优。
否则,令 n = 2 ^ K - 1 + x,那么对于2 ^ K - 1部分来说,切 K - 1 次就可以实现对 n - x 部分的任意称量了,因为 n - x 一定不会小于 x,所以剩下的x不需要再切了。一开始将 n 分成 2 ^ K 和 x 需要1次,切 2 ^ K - 1 需要K - 1次,所以总共需要切 K 次。

 

(这个当时是我队友给我讲的,不是很确定,我数学不好= =)

 

时间复杂度 = O(logN)

 

J) 蛇行矩阵

 

每行数字之间的差值是个等差数列。
第一列每个数字之间的差值也是个等差数列。
找出通项公式用两层 for 循环直接打出来即可。

 

时间复杂度 = O(n ^ 2)


为解题报告打分
暂时不评分

★★
★★★
★★★★
★★★★★
发表您的评论(若贴AC代码或发表禁止言论等违禁行为将被删除并扣除积分)

|返回 |   | 转到页头|
Copyright @ 2008-2024(浙ICP备2022001332号), TZOJ. All Rights Reserved.