0%

The 2014 ACMICPC Asia Regional Xian Online

【A】签到题

【B】后缀数组

【C】染色,DP(感觉可出)

【D】BFS搜索,有点麻烦

【E】博弈论,Nim博弈

【F】BFS状态搜索

【G】概率DP+状态压缩

【H】异或+构造

【I】矩阵快速幂(队友已出)

【J】树的分治

【K】类模拟退火的方向修正搜索、三分


A、Post Robot

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Problem Description

DT is a big fan of digital products. He writes posts about technological products almost everyday in his blog.

But there is such few comments of his posts that he feels depressed all the day. As his best friend and an excellent programmer, DT asked you to help make his blog look more popular. He is so warm that you have no idea how to refuse. But you are unwilling to read all of his boring posts word by word. So you decided to write a script to comment below his posts automatically.

After observation, you found words “Apple” appear everywhere in his posts. After your counting, you concluded that “Apple”, “iPhone”, “iPod”, “iPad” are the most high-frequency words in his blog. Once one of these words were read by your smart script, it will make a comment “MAI MAI MAI!”, and go on reading the post.

In order to make it more funny, you, as a fan of Sony, also want to make some comments about Sony. So you want to add a new rule to the script: make a comment “SONY DAFA IS GOOD!” when “Sony” appears.

Input

A blog article described above, which contains only printable characters(whose ASCII code is between 32 and 127), CR(ASCII code 13, ‘\r’ in C/C++), LF(ASCII code 10, ‘\n’ in C/C++), please process input until EOF. Note all characters are case sensitive.

The size of the article does not exceed 8KB.

Output

Output should contains comments generated by your script, one per line.

Sample Input

Apple bananaiPad lemon ApplepiSony
233
Tim cook is doubi from Apple
iPhoneipad
iPhone30 is so biiiiiiig Microsoft
makes good App.

Sample Output

MAI MAI MAI!
MAI MAI MAI!
MAI MAI MAI!
SONY DAFA IS GOOD!
MAI MAI MAI!
MAI MAI MAI!
MAI MAI MAI!

分析

买买买!!!

直接扫描判断即可。


E、Game

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Problem Description

Here is a game for two players. The rule of the game is described below:

  • In the beginning of the game, there are a lot of piles of beads.
  • Players take turns to play. Each turn, player choose a pile i and remove some (at least one) beads from it. Then he could do nothing or split pile i into two piles with a beads and b beads.(a,b > 0 and a + b equals to the number of beads of pile i after removing)
  • If after a player’s turn, there is no beads left, the player is the winner.

Suppose that the two players are all very clever and they will use optimal game strategies. Your job is to tell whether the player who plays first can win the game.

Input

There are multiple test cases. Please process till EOF.

For each test case, the first line contains a postive integer n(n < 105) means there are n piles of beads. The next line contains n postive integer, the i-th postive integer ai(ai < 231) means there are ai beads in the i-th pile.

Output

For each test case, if the first player can win the game, ouput “Win” and if he can’t, ouput “Lose”

Sample Input

1
1
2
1 1
3
1 2 3

Sample Output

Win
Lose
Lose

题意

取石子的游戏:初始时有n堆,每人轮流进行取的过程,每次可以选择某一堆取任意个,然后选择把剩下的部分分成任意数量的两堆。最后一个取完所有东西的人获胜。

分析

妈蛋!!!比赛前我根本没听说过Nim博弈好么!!!果然还是题目做的太少T_T,东西了解得太少T_T////////////////////////

看着别人刷刷刷都过了,死活看不明白是怎么回事……哭晕在厕所啊

以下是两个博弈论知识的总结帖:

http://blog.csdn.net/u012860063/article/details/21816635

http://blog.csdn.net/chao1983210400/article/details/10284693

启发

……还是多做题吧,没见过只能怪自己没见过。


F、Dice

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Problem Description

There are 2 special dices on the table. On each face of the dice, a distinct number was written. Consider a1.a2,a3,a4,a5,a6 to be numbers written on top face, bottom face, left face, right face, front face and back face of dice A. Similarly, consider b1.b2,b3,b4,b5,b6 to be numbers on specific faces of dice B. It’s guaranteed that all numbers written on dices are integers no smaller than 1 and no more than 6 while ai ≠ aj and bi ≠ bj for all i ≠ j. Specially, sum of numbers on opposite faces may not be 7.

At the beginning, the two dices may face different(which means there exist some i, ai ≠ bi). Ddy wants to make the two dices look the same from all directions(which means for all i, ai = bi) only by the following four rotation operations.(Please read the picture for more information)

dice

Now Ddy wants to calculate the minimal steps that he has to take to achieve his goal.

Input

There are multiple test cases. Please process till EOF.

For each case, the first line consists of six integers a1,a2,a3,a4,a5,a6, representing the numbers on dice A.

The second line consists of six integers b1,b2,b3,b4,b5,b6, representing the numbers on dice B.

Output

For each test case, print a line with a number representing the answer. If there’s no way to make two dices exactly the same, output -1.

Sample Input

1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6
1 2 5 6 4 3
1 2 3 4 5 6
1 4 2 5 3 6

Sample Output

0
3
-1

题意

给出四种筛子翻转的方案,给出两种筛子的状态,要求判断是否可以从一个状态操作到另一个。输出最少操作步数或者-1(不可能)。

分析

看到题目的第一感觉就是这种题肯定没办法直接通过数学上的关系解决,每种状态是6个数字,最多也就是6^6=46k多一点种,而实际上筛子有严格的对应关系,所以实际的状态量要比这个还少一点。

于是采用BFS扩展状态即可,中间最重要的就是注意判重就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : F1006
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef struct nod{
int a,b,c,d,e,f;
} node;

node move1(node a)
{
node ret;
ret.a=a.d;ret.b=a.c;ret.c=a.a;
ret.d=a.b;ret.e=a.e;ret.f=a.f;
return ret;
}

node move2(node a)
{
node ret;
ret.a=a.c;ret.b=a.d;ret.c=a.b;
ret.d=a.a;ret.e=a.e;ret.f=a.f;
return ret;
}

node move3(node a)
{
node ret;
ret.a=a.f;ret.b=a.e;ret.c=a.c;
ret.d=a.d;ret.e=a.a;ret.f=a.b;
return ret;
}

node move4(node a)
{
node ret;
ret.a=a.e;ret.b=a.f;ret.c=a.c;
ret.d=a.d;ret.e=a.b;ret.f=a.a;
return ret;
}

node q[50000];
int num[50000];
int head=1,tail=1;

bool check(node a)
{
for (int i=1;i<=tail;i++)
if (a.a==q[i].a&&a.b==q[i].b&&a.c==q[i].c&&a.d==q[i].d&&a.e==q[i].e&&a.f==q[i].f)
return true;
return false;
}

int main()
{
node a,b;
while (scanf("%d",&a.a)!=EOF)
{
scanf("%d%d%d%d%d",&a.b,&a.c,&a.d,&a.e,&a.f);
scanf("%d%d%d%d%d%d",&b.a,&b.b,&b.c,&b.d,&b.e,&b.f);

if (a.a==b.a&&a.b==b.b&&a.c==b.c&&a.d==b.d&&a.e==b.e&&a.f==b.f)
{
printf("0\n");
} else
{
q[1]=a;
num[1]=0;
bool done=false;
head=1;tail=1;
while (head<=tail)
{
node temp=move1(q[head]);
if (temp.a==b.a&&temp.b==b.b&&temp.c==b.c&&temp.d==b.d&&temp.e==b.e&&temp.f==b.f)
{
printf("%d\n",num[head]+1);
done=true;
break;
}
if (!check(temp))
{
tail++;
q[tail]=temp;
num[tail]=num[head]+1;
}

temp=move2(q[head]);
if (temp.a==b.a&&temp.b==b.b&&temp.c==b.c&&temp.d==b.d&&temp.e==b.e&&temp.f==b.f)
{
printf("%d\n",num[head]+1);
done=true;
break;
}
if (!check(temp))
{
tail++;
q[tail]=temp;
num[tail]=num[head]+1;
}

temp=move3(q[head]);
if (temp.a==b.a&&temp.b==b.b&&temp.c==b.c&&temp.d==b.d&&temp.e==b.e&&temp.f==b.f)
{
printf("%d\n",num[head]+1);
done=true;
break;
}
if (!check(temp))
{
tail++;
q[tail]=temp;
num[tail]=num[head]+1;
}

temp=move4(q[head]);
if (temp.a==b.a&&temp.b==b.b&&temp.c==b.c&&temp.d==b.d&&temp.e==b.e&&temp.f==b.f)
{
printf("%d\n",num[head]+1);
done=true;
break;
}
if (!check(temp))
{
tail++;
q[tail]=temp;
num[tail]=num[head]+1;
}

head++;
}
if (!done) printf("-1\n");
}
}

return 0;
}

代码写得也比较丑

启发

当时初看题目的时候瞟了几眼直接就跳过了,-_-///事后感觉没什么可以做了才回来看的,然后才发现其实很简单。还是应该认真看看题,比赛的时候至少每道题都要看过去,说不定能找到一些突破点。


H、Number Sequence

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Special Judge

Problem Description

There is a special number sequence which has n+1 integers. For each number in sequence, we have two rules:

  • ai ∈ [0,n]
  • ai ≠ aj( i ≠ j )

For sequence a and sequence b, the integrating degree t is defined as follows(“⊕” denotes exclusive or):

t = (a0 ⊕ b0) + (a1 ⊕ b1) +···+ (an ⊕ bn)

(sequence B should also satisfy the rules described above)

Now give you a number n and the sequence a. You should calculate the maximum integrating degree t and print the sequence b.

Input

There are multiple test cases. Please process till EOF.

For each case, the first line contains an integer n(1 ≤ n ≤ 105), The second line contains a0,a1,a2,…,an.

Output

For each case, output two lines.The first line contains the maximum integrating degree t. The second line contains n+1 integers b0,b1,b2,…,bn. There is exactly one space between bi and bi+1(0 ≤ i ≤ n - 1). Don’t ouput any spaces after bn.

Sample Input

4
2 0 1 4 3

Sample Output

20
1 0 2 3 4

题意

题目给出一组A序列,t的值是等于B序列中的每一个对应的数与A序列异或之后的和。现在的要求就是求出能够使得t最大的B序列。

分析

首先我真的不是特别明白这道题为什么会用到Special Judge?

……按照我的想法,能使得t最大的B序列应该是唯一的,把所有数都化为二进制的形式,则为了使得Ai异或Bi的值最大,Bi的二进制数位要尽可能多地与Ai错开。

所以这样出来的数其实是一组两个的数,A序列是从0到n,B序列也是从0到n,且每个序列不出现重复的数字。对于每一个Ai,用一个等长的全1的二进制数去与之异或,就能得到对应的Bi,反过来对数Bi操作可以得到数Ai。其实就是构造出来之后使对应的Ai+Bi能等于一个全是1的二进制数。

如此就能构造出B序列了,下面是几个序列的对应关系,T这行表示异或结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
n=7
-------------------
A 0 1 2 3 4 5 6 7

B 7 6 5 4 3 2 1 0

T 7 7 7 7 7 7 7 7
-------------------
n=8
-------------------
A 0 1 2 3 4 5 6 7 8

B 0 6 5 4 3 2 1 8 7

T 0 7 7 7 7 7 7 15 15
-------------------
n=9
-------------------
A 0 1 2 3 4 5 6 7 8 9

B 1 0 5 4 3 2 9 8 7 6

T 1 1 7 7 7 7 15 15 15 15
-------------------

当然这里有个顺序的问题,构造的时候从最大(二进制最长的数)的开始向小的数进行,保证使最终总的异或值最大,并且后来构造出来Bi的数比Ai小,避免了异或构造出来的数大于n的情况(真的可能会有啊)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : H1008
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int pp[]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535,131071};
int a[100010],b[100010];

int get(int s)
{
int ret=0;
while (s>0)
{
ret++;
s/=2;
}
return ret;
}

int main()
{
//freopen("H1008.txt","r",stdin);
//freopen("H1008out.txt","w",stdout);

int n;
while (scanf("%d",&n)!=EOF)
{
memset(a,0,sizeof(a));
for (int i=n;i>=0;i--)
if (!a[i])
{
for (int j=i;j>=pp[get(i)-1]+1;j--)
{
int yh=j^pp[get(i)];
a[j]=yh;
a[yh]=j;
}
}

long long ans=0;
int x;
for (int i=0;i<=n;i++)
{
scanf("%d",&x);
//x=i;
ans+=(long long )x^a[x];
b[i]=a[x];
}
printf("%lld\n",ans);
printf("%d",b[0]);
for (int i=1;i<=n;i++) printf(" %d",b[i]);
printf("\n");
}

return 0;
}

启发

虽然当时还没想明白Special Judge是为什么(现在还是不明白…),不过以后碰到有思路的就直接上吧,说不定就对了呢。


K、Ellipsoid

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Special Judge

Problem Description

Given a 3-dimension ellipsoid(椭球面)

elli

your task is to find the minimal distance between the original point (0,0,0) and points on the ellipsoid. The distance between two points (x1,y1,z1) and (x2,y2,z2) is defined as

define

Input

There are multiple test cases. Please process till EOF.

For each testcase, one line contains 6 real number a,b,c(0 < a,b,c,< 1),d,e,f(0 ≤ d,e,f < 1), as described above. It is guaranteed that the input data forms a ellipsoid. All numbers are fit in double.

Output

For each test contains one line. Describes the minimal distance. Answer will be considered as correct if their absolute error is less than 10-5.

Sample Input

1 0.04 0.01 0 0 0

Sample Output

1.0000000

题意

题目给出一个椭圆面的空间方程,要求计算出原点与椭圆面之间的最短距离。

分析

数学上的正解应该是解拉格朗日乘数法在附加条件下的多元函数极值。

网上给出的题解大多有两种:模拟退火、三分。这两种算法在一定程度上都有问题。

先说这个:

模拟退火

一般的搜索都是完全朝着最优解去的,但是在某些情况下,这样就可能存在一个问题:可能当前得到的最优解只是局部的,无法得到全局的最优解。类似贪心算法的问题。

当然这样的情况不太常见。

然后模拟退火的核心是:以一定概率接受向着非最优解的方向移动,这里涉及到一个退火温度的概念。初始时温度较高,向非最优解方向移动的概率也较高,随着搜索层数的增加,可以认为离最优解越来越近了,温度逐渐下降,非最优解跳转的概率也会逐渐下降。

但是搜遍了网上关于本题的模拟退火代码,貌似都是一个版本出来的……-_-//////

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : HDU5017-Easy Simulated Annealing
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

double a,b,c,d,e,f;
double r=0.99;
double eps=1e-8;
int dx[]={-1,-1,-1,0,0,1,1,1};
int dy[]={-1,0,1,-1,1,-1,0,1};

double cal(double x,double y)
{
double A=c,B=e*x+d*y,C=a*x*x+b*y*y+f*x*y-1;
double delta=B*B-4*A*C;
if (delta<0) return 1e60;
double z1=(-B+sqrt(delta))/2/A,z2=(-B-sqrt(delta))/2/A;
if (z1*z1<z2*z2) return z1;
else return z2;
}

double dis(double x,double y,double z)
{
return sqrt(x*x+y*y+z*z);
}

double doit()
{
double step=1;
double x=0,y=0,z;
while (step>eps)
{
z=cal(x,y);
for (int i=0;i<8;i++)
{
double xx=x+dx[i]*step,yy=y+dy[i]*step;
double zz=cal(xx,yy);
if (zz>1e30) continue;
if (dis(xx,yy,zz)<dis(x,y,z))
{
x=xx;
y=yy;
z=zz;
}
}
step*=r;
}
return dis(x,y,z);
}

int main()
{
while (scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&e,&f)!=EOF)
printf("%.8f\n",doit());
return 0;
}

个人认为这种搜索策略与真正的模拟退火算法还是有一点区别的,首先这里面根本没有涉及到向非最优解方向移动的情况。

我的理解是,这里模仿了模拟退火算法对温度控制的特性。由于是求解原点与椭球面的距离,这个结果必然是一个凸函数,则不断修正前进的方向并逐步缩小搜索范围,最终到达最优解。

首先指定一个步长与步长衰减速度(类退火速度),每次搜索完成一层,步长衰减一次,直到衰减程度在精度控制范围内。

三分

二分用来求解线性函数的最优值,三分则是用来求解凸函数的最优值。

对于本题来说,基本想法是以x,y,z中的其中两个变量进行两次三分,而后计算出第三个变量,并以最终的距离作为判断函数。由于这里都是实数,两层三分需要迭代的次数比较难以控制,参数稍微修正得不对,精度与时间上就会出现比较大的问题,这两个要求的参数是对立的,精度高了耗时就长,时间控制了,可能最终结果又错了。

最后提交的是在超时边缘……中间出现了许多重复运算,这种还是不推荐使用了。