The 2014 ACM-ICPC Asia Mudanjiang Regional First Round

【A】签到题

【B】构造

【C】遍历+floodfill染色或并查集

【D】DP(背包)+状态压缩 (感觉可出)

【E】线段树

【F】图形题 搜索+状态压缩

【G】数论,某种不定方程......ZOJ上到现在只过了4个人,还找不到题解-_-///

【H】回文数变种+dfs枚举构造 又是构造-_-///

【I】字符串哈希+DP或者暴力

【J】直接模拟,字符串细节操作

 

【A】

The Himalayas

Time Limit: 2 Seconds                                     Memory Limit: 65536 KB                            

As an artist, Bob usually need to travel around the world. He made a lot of sketch of scenery on his journey. A famous spot he have visited recently is the Himalayas. The Himalayas is a mountain range in South Asia separating the plains of the Indian subcontinent from the Qinghai-Tibet Plateau. The Himalayas include over a hundred mountains exceeding 7,200 meters in elevation.

One day, Bob came up with an strange idea. He wanted to know the number of mountain peaks in his paintings. As his best friend, he turned to you for help. You are given a list of N height sampling values Hi. You should determine how many peaks are there. For all i which satisfies 2 <= i <= N - 1, Hi is defined as a peak if and only if Hi-1 < Hi > Hi+1.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains one integer N (1 <= N <= 50). The next line contains N integers Hi (1 <= Hi <= 8844). It is guaranteed that any two adjacent height sampling values will be different.

Output

For each test case, output the number of peaks.

Sample Input

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

Sample Output

3
0

【题意】

给出一系列地形的高度,要求找到山峰的个数

【分析】

稍微判断一下即可。

 

【B】

A Volcanic Island

Time Limit: 2 Seconds      Memory Limit: 65536 KB      Special Judge

An underwater volcano has erupted massively in somewhere of the deep Atlantis Ocean. This large eruption led to the birth of a new volcanic island, which had a shape of square. Near the island, there are N countries. All of them have claimed the sovereignty over the island.

After a lot of multilateral negotiation and occasional armed conflicts, the N countries decided to divide the square volcanic island equally. They partitioned the island into N x N small equal-sized square chunks. Each country could get a connected region consists of exact N chunks.

Two chunks A and B are called "connected" if they share an edge, or there exists another chunk C connected with both A and B. A group of chunks are called "connected region" if any two of these chunks are connected.

Every country want a unique region. It means the N regions should be different with each other. Two regions are considered as the same if and only if one can transform into the other by an isometry (a combination of rigid motions, including translation, rotation and reflection).

In a nutshell, your task is to divide a square island with N x N chunks into N connected regions with different shape. You also need to draw a map to color the regions of the map so that no two edge-adjacent regions have the same color. Most of the people in these countries believed that four different colors are enough. So you can mark these regions with at most four colors, red, green, blue and yellow.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

There is only an integer N (1 <= N <= 100).

Output

For each test case, output a valid map described above. If there is no solution, output "No solution!" instead. Please note that only four colors ('R', 'G', 'B' and 'Y') can be used to drawing the map.

Sample Input

2
2
5

Sample Output

No solution!
YYYGR
YGGGR
YGYYR
BYYYR
BBBBR

【题意】

给出一张n*n的图,要求用4种颜色去染色,染色之后将图分成n个总数为n的颜色块。另外的一个重要要求就是这n个色块的形状不能出现重复。

【分析】

本题采用的是special judge,所以需要自己构造出一种方案来对其进行染色。

赛后参考其他大神的想法,构造方案如下:

以7和8为例:

首先将其中的最后一列全部记为一种颜色,剩下的n*(n-1)部分用另外3种颜色去染:

前n/2种区块蛇形染色:

 1 n=7
 2 -------
 3 1111110
 4 2222210
 5 2233330
 6 xxx3330
 7 xxxxxx0
 8 xxxxxx0
 9 xxxxxx0
10 -------
11 n=8
12 --------
13 11111110
14 22222210
15 22333330
16 44443330
17 4444xxx0
18 xxxxxxx0
19 xxxxxxx0
20 xxxxxxx0
21 --------

后n/2块一行一行从左向右将剩下部分填满

 1 n=7
 2 -------
 3 111111 0
 4 222221 0
 5 223333 0
 6    333 0
 7 444
 8 554444 0
 9 655555 0
10 666666 0
11 -------
12 n=8
13 --------
14 1111111 0
15 2222221 0
16 2233333 0
17 4444333 0
18 4444
19     555 0
20 5555566 0
21 6666667 0
22 7777777 0
23 --------

以上n=7和n=8时最后对齐的方向与第一部分最后一行染色的方向相同。

接下来需要注意的就是第一块与最后一块的形状相同,于是作一下微调把它们变得不一样即可:

 1 n=7
 2 -------
 3 1111110
 4 2222210
 5 2233330
 6 4443330
 7 6544440
 8 6555550
 9 6666650
10 -------
11 n=8
12 --------
13 11111110
14 22222210
15 22333330
16 44443330
17 44445550
18 55555670
19 66666670
20 67777770

我的做法是把最后一块色块在最后一行的其中一块与最后第二块色块在n-2行的其中一块进行互换,保证相同颜色这时候还是连在一起的就行。

测试时,发现n等于5和6时,用这种调整方案是不行的,因为格子数太少,会出现第一块与最后一块颜色相同然后重叠到一起的情况。对包括这个在内的几种情况进行一下特判即可。

  1 /* ***********************************************
  2 MYID    : Chen Fan
  3 LANG    : G++
  4 PROG    : ZOJ3810
  5 ************************************************ */
  6 
  7 /*
  8     1111110
  9     2222210
 10     2233330
 11     4443330
 12     6544440
 13     6555550
 14     6666650
 15 
 16     11111110
 17     22222210
 18     22333330
 19     44443330
 20     44445550
 21     55555670
 22     66666670
 23     67777770
 24 */
 25 
 26 #include<iostream>
 27 #include<cstdio>
 28 #include<cstring>
 29 #include<algorithm>
 30 
 31 using namespace std;
 32 
 33 int a[110][110];
 34 
 35 int main()
 36 {
 37     int t;
 38     scanf("%d",&t);
 39     for (int tt=1;tt<=t;tt++)
 40     {
 41         int n;
 42         scanf("%d",&n);
 43 
 44         if (n==1) printf("Y\n");
 45         else if (n==2||n==3||n==4) printf("No solution!\n");
 46         else if (n==5) printf("YYYGR\nYGGGR\nYGYYR\nBYYYR\nBBBBR\n");
 47         else if (n==6) printf("RRRRRY\nRGGGGY\nGGRRRY\nRRRGBY\nGGGGBY\nGBBBBY\n");
 48         else 
 49         {
 50             memset(a,0,sizeof(a));
 51 
 52             int x=1,y=1,fx=1;
 53             for (int i=1;i<=n/2;i++)
 54             for (int j=1;j<=n;j++)
 55             {
 56                 a[x][y]=i;
 57                 y+=fx;
 58                 if ((y==n&&fx==1)||(y==0&&fx==-1))
 59                 {
 60                     x++;
 61                     fx=-fx;
 62                     y+=fx;
 63                 }
 64             }
 65             
 66             for (int i=n/2+1;i<n;i++)
 67             for (int j=1;j<=n;j++)
 68             {
 69                 a[x][y]=i;
 70                 y+=fx;
 71                 if ((y==n&&fx==1)||(y==0&&fx==-1)) 
 72                 {
 73                     x++;
 74                     y=n-y+fx;
 75                 }
 76             }
 77 
 78             if (fx==-1)
 79             {
 80                 a[n-2][1]=n-1;
 81                 a[n][n-1]=n-2;
 82             } else 
 83             {
 84                 a[n-2][n-1]=n-1;
 85                 a[n][1]=n-2;
 86             }
 87 
 88             char words[]={'R','G','B'};
 89             for (int i=1;i<=n;i++)
 90             {
 91                 for (int j=1;j<=n;j++)
 92                 if (a[i][j]==0) printf("Y");
 93                 else printf("%c",words[a[i][j]%3]);
 94                 printf("\n");
 95             }
 96             
 97         }
 98     }
 99 
100     return 0;
101 }
View Code

【赛后启发】

以后碰到这种需要自己进行构造的题目不要直接就放弃,感觉稍微花点时间还真是能想出来的,,,这种纠结程度就跟贪心似地,,,如果没别的题能做了,至少随便构造一个交一下看看呗。 

 

【C】

Untrusted Patrol

Time Limit: 3 Seconds                                     Memory Limit: 65536 KB                            

Edward is a rich man. He owns a large factory for health drink production. As a matter of course, there is a large warehouse in the factory.

To ensure the safety of drinks, Edward hired a security man to patrol the warehouse. The warehouse has N piles of drinks and M passageways connected them (warehouse is not big enough). When the evening comes, the security man will start to patrol the warehouse following a path to check all piles of drinks.

Unfortunately, Edward is a suspicious man, so he sets sensors on K piles of the drinks. When the security man comes to check the drinks, the sensor will record a message. Because of the memory limit, the sensors can only record for the first time of the security man's visit.

After a peaceful evening, Edward gathered all messages ordered by recording time. He wants to know whether is possible that the security man has checked all piles of drinks. Can you help him?

The security man may start to patrol at any piles of drinks. It is guaranteed that the sensors work properly. However, Edward thinks the security man may not works as expected. For example, he may digs through walls, climb over piles, use some black magic to teleport to anywhere and so on. 

Input

There are multiple test cases. The first line of input is an integer T indicates the number of test cases. For each test case:

The first line contains three integers N (1 <= N <= 100000), M (1 <= M <= 200000) and K (1 <= K <= N).

The next line contains K distinct integers indicating the indexes of piles (1-based) that have sensors installed. The following M lines, each line contains two integers Ai and Bi (1 <= Ai, Bi <= N) which indicates a bidirectional passageway connects piles Ai and Bi.

Then, there is an integer L (1 <= L <= K) indicating the number of messages gathered from all sensors. The next line contains L distinct integers. These are the indexes of piles where the messages came from (each is among the K integers above), ordered by recording time.

Output

For each test case, output "Yes" if the security man worked normally and has checked all piles of drinks, or "No" if not.

Sample Input

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

Sample Output

No
Yes

【题意】

给出一张图,图中的某些结点上装着传感器,访问到装着传感器的节点时,就会被记录下来。现在给出一串传感器记录下来的时间访问序列,询问一个人是否能够按照序列的顺序遍历完整张图。

【分析】

1.floodfill染色:

当时看到这道题想到的只有暴力DFS,写出来之后发现由于floodfill染色的性质,每个点只是访问一次就够了,效率还是很优的。

 

基本想法是从时间序列第一个点开始,按时间顺序扩展每一个点,所有标记着传感器的点不可达。扩展完第一个点之后,判断一下下一个点是否能够到达,若不能到达即说明按顺序遍历不可能;否则继续扩展下一个点。

 

对每一个结点设置四种标记:无标记、已访问、不可访问、能够访问;

普通点在到达之前无标记,到达之后标记为已访问;传感器结点在到达之前标记为不可访问,到达之后标记为能够访问,搜过之后标记为已访问;

一、直接搜索L个传感器的序列,首先将所有拥有传感器的序列全部标记为不可访问;

二、从第一个开始,扩展遍历所有能到达的点,遍历时的点有两种状态:无标记(普通点)和不可/能够访问(带有传感器的点)。无标记点可以直接改为已访问,不可访问的点则标记为能够访问。遍历完之后将该传感器点标为已访问;

三、判断下一个传感器点的状况是不是能够访问,若是则表示可以从之前的传感器点不经过任何序列后面的点而到达,若标记是不可访问则表示不可能从之前的传感器点到达这里,那就直接输出NO了。

四、之后重复二、三过程,直到搜完所有L个点,判断整张图的连通性,即是不是所有点都能到达。

对于K和L,个人觉得描述的最后一句是有用的,就是L只会小于等于K,不一定要等于K。然后第一次没有加这个特判,结果WA了......加上之后AC,-_-////真的是我想多了吗

然后就是前向星存储。

  1 /* ***********************************************
  2 MYID    : Chen Fan
  3 LANG    : G++
  4 PROG    : ZOJ3811
  5 ************************************************ */
  6 
  7 #include <iostream>
  8 #include <cstdio>
  9 #include <cstring>
 10 #include <algorithm>
 11 
 12 using namespace std;
 13 
 14 typedef struct nod
 15 {
 16     int x,y;
 17 } node;
 18 node a[400010];
 19 int start[100010],num[100010];
 20 unsigned short flag[100010];
 21 
 22 int sen[100010];
 23 
 24 bool op(node a,node b)
 25 {
 26     if (a.x==b.x) return a.y<b.y;
 27     else return a.x<b.x;
 28 }
 29 
 30 void dfs(int s)
 31 {
 32     flag[s]=3;
 33     for (int i=0;i<num[s];i++)
 34     {
 35         int next=a[start[s]+i].y;
 36         if (flag[next]==0) dfs(next);
 37         else if (flag[next]==1) flag[next]=2;
 38     }
 39 }
 40 
 41 int main()
 42 {
 43     int t;
 44     scanf("%d",&t);
 45     for (int tt=1;tt<=t;tt++)
 46     {
 47         int n,m,k;
 48         scanf("%d%d%d",&n,&m,&k);
 49         for (int i=1;i<=k;i++) scanf("%d",&sen[i]);
 50         for (int i=1;i<=m;i++)
 51         {
 52             int x,y;
 53             scanf("%d%d",&x,&y);
 54             a[i*2].x=x;
 55             a[i*2].y=y;
 56             a[i*2-1].x=y;
 57             a[i*2-1].y=x;
 58         }
 59         
 60         int l;
 61         scanf("%d",&l);
 62         
 63         memset(flag,0,sizeof(flag));
 64         for (int i=1;i<=l;i++)
 65         {
 66             scanf("%d",&sen[i]);
 67             flag[sen[i]]=1;
 68         }
 69         
 70         if (l<k)
 71         {
 72             printf("No\n");
 73             continue;
 74         }
 75         
 76         m*=2;
 77         memset(start,0,sizeof(start));
 78         memset(num,0,sizeof(num));
 79         sort(&a[1],&a[m+1],op);
 80         int o=0;
 81         for (int i=1;i<=m;i++)
 82         {
 83             if (o!=a[i].x) 
 84             {
 85                 o=a[i].x;
 86                 start[o]=i;
 87             }
 88             num[o]++;
 89         }
 90         
 91         flag[sen[1]]=2;
 92         bool outp=true;
 93         for (int i=1;i<=l;i++)
 94         if (flag[sen[i]]==2) dfs(sen[i]);
 95         else 
 96         {
 97             outp=false;
 98             break;
 99         }
100         
101         if (outp)
102         for (int i=1;i<=n;i++) 
103         if (flag[i]!=3)
104         {
105             outp=false;
106             break;
107         }
108         
109         if (outp) printf("Yes\n");
110         else printf("No\n");
111     }
112     
113     return 0;
114 }
View Code

 

2.并查集

大体思路与上面类似,把1中的染色部分改成扩展一个可以任意到达的无限集即可。

【启发】

题目中给出了明显的顺序的话,可以作为一个突破点。

 

【H】

Generalized Palindromic Number

Time Limit: 2 Seconds      Memory Limit: 65536 KB

A number that will be the same when it is written forwards or backwards is known as a palindromic number. For example, 1234321 is a palindromic number.

We call a number generalized palindromic number, if after merging all the consecutive same digits, the resulting number is a palindromic number. For example, 122111 is a generalized palindromic number. Because after merging, 122111 turns into 121 which is a palindromic number.

Now you are given a positive integer N, please find the largest generalized palindromic number less than N.

Input

There are multiple test cases. The first line of input contains an integer T (about 5000) indicating the number of test cases. For each test case:

There is only one integer N (1 <= N <= 1018).

Output

For each test case, output the largest generalized palindromic number less than N.

Sample Input

4
12
123
1224
1122

Sample Output

11
121
1221
1121

【题意】

如果一个数把相邻数位相同的部分都合并之后它还是一个回文数,那就称其为广义回文数。现在给出一个n,要求找到小于n的最大的广义回文数。

【分析】

开始时想从某种贪心的方法出发手动构造这样一个数出来,很可惜失败了,这里每次摆数字的判断有些麻烦。

 

赛后尝试用DFS进行构造:

每次从前后同时向中间构造,保证回文性。构造时先在高位摆上一个值,然后从低位向中间摆相同的数,中间注意剪枝判断。

注意摆值的时候上限与更高一位是不是与n相应位相同有关。如果前一位与原数不同,则可以从9开始摆,否则不能比原数大。

 1 /* ***********************************************
 2 MYID    : Chen Fan
 3 LANG    : G++
 4 PROG    : ZOJ3816
 5 ************************************************ */
 6 
 7 #include <iostream>
 8 #include <cstdio>
 9 #include <cstring>
10 #include <algorithm>
11 
12 using namespace std;
13 
14 int tail,nn[30],num[30],ans[30];
15 
16 bool check(int a[],int b[],int l,int r) 
17 {
18     for (int i=r;i>=l;i--) 
19     if (a[i]!=b[i]) return a[i]>b[i];
20     return false;
21 }
22 
23 void dfs(int high,int low,bool flag)
24 {
25     if (high<low)
26     {
27         if (check(nn,num,1,tail)&&check(num,ans,1,tail))
28         for (int i=1;i<=tail;i++) ans[i]=num[i];
29     } else
30     {
31         int end;
32         if (flag) end=nn[high];
33         else end=9;
34 
35         for (int i=end;i>=0;i--)
36         {
37             int now=low;
38             if (check(ans,num,high+1,tail)) return;
39 
40             num[high]=i;
41             if (num[high]!=num[high+1])
42             {
43                 while (now<=high)
44                 {
45                     num[now]=num[high];
46                     now++;
47                     dfs(high-1,now,flag&&i==end);
48                 }
49             } else dfs(high-1,low,flag&&i==end);
50         }
51     }
52 }
53 
54 int main()
55 {
56     int t;
57     scanf("%d",&t);
58     
59     for (int tt=1;tt<=t;tt++)
60     {
61         long long n;
62         scanf("%llu",&n);
63         
64         tail=0;
65         while(n)
66         {
67             tail++;
68             nn[tail]=n%10;
69             n/=10;
70         }
71         
72         memset(num,0,sizeof(num));
73         memset(ans,0,sizeof(ans));
74         dfs(tail,1,1);
75         for (int i=tail;i>=1;i--) printf("%d",ans[i]);
76         printf("\n");
77     }
78     
79     return 0;
80 }
View Code

【启发】
实在不行可以暴搜啊!!!!!

 

【J】

Pretty Poem

Time Limit: 2 Seconds                                     Memory Limit: 65536 KB                            

Poetry is a form of literature that uses aesthetic and rhythmic qualities of language. There are many famous poets in the contemporary era. It is said that a few ACM-ICPC contestants can even write poetic code. Some poems has a strict rhyme scheme like "ABABA" or "ABABCAB". For example, "niconiconi" is composed of a rhyme scheme "ABABA" with A = "ni" and B = "co".

More technically, we call a poem pretty if it can be decomposed into one of the following rhyme scheme: "ABABA" or "ABABCAB". The symbol A, B and C are different continuous non-empty substrings of the poem. By the way, punctuation characters should be ignored when considering the rhyme scheme.

You are given a line of poem, please determine whether it is pretty or not.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

There is a line of poem S (1 <= length(S) <= 50). S will only contains alphabet characters or punctuation characters.

Output

For each test case, output "Yes" if the poem is pretty, or "No" if not.

Sample Input

3
niconiconi~
pettan,pettan,tsurupettan
wafuwafu

Sample Output

Yes
Yes
No

【分析】

由于本题数据量最大只有50个字符,可以直接模拟枚举。

首先枚举AB,满足AB匹配之后,再判断AB长度的三倍与总长度之间的关系,分类讨论。

算法就是这么个算法,但是实现起来超容易出错......

附上一组处理得比较全面的测试数据

1 8
2 xyxyxxy
3 xyxyyxy
4 xxxxyxx
5 xxxxx
6 xyxyx
7 xxxxxxxx
8 xxxxxxxxxxxxx
9 xyzzxyzxyzzxyzxyzxyzzxyz

 【启发】

题目数据量才这么点。。。果断应该直接上的

posted @ 2014-09-08 11:24  辰帆  阅读(7483)  评论(1编辑  收藏  举报