出题组说难度顺序是ABIC EH FG D
不过这里还是按照题目顺序
如果遇见不懂的神秘词汇(例如尺取) 请百度“acm 尺取”
代码我会只留必要的定义并且尽量减短长度
A
Unsolved Problem
Description
Ly is participating in a programming game!
The programming game includes n problems numbered from 1 to n, and Ly has already solved some of them.
You need to find out the lowest numbered problem that Ly has not yet solved.
Input
The first line contains a integer T — the number of cases.
For each case, the first line contains two integers n and k — the number of total problems in the programming game, and the number of problems Ly has already solved.
The nextline contains k ascending integers, represents the problems Ly has already solved.
0 <= k < n <= 100
Output
Output an integer, represents the lowest numbered problem that Ly has not yet solved.
Sample Input 1
3
5 3
1 2 3
6 3
2 3 4
7 5
1 2 3 4 6
Sample Output 1
4
1
5
Source
Ly
题意:有1-n中出现了m个数 让你找到最小的没出现过的数
做法:直接模拟即可
代码:
bool a[200];
int main() {
int t;
cin>>t;
while(t--) {
int n;
cin>>n;
int m;
cin>>m;
for(int i=1; i<=n; ++i)a[i] = 0;
for(int i=1; i<=m; ++i) {
int x;
cin>>x;
a[x] = 1;
}
for(int i=1; i<=n; ++i) {
if(a[i]==0) {
printf("%d\n",i);
break;
}
}
}
return 0;
}
B
Square Game
Description
Sweetzero and Takio are thinking about a hard promblem !
Given n 1x1 squares, Sweetzero needs to use them to form a connected graph with longest perimeter, and Takio needs to use them to form a connected graph with the smallest perimeter.
A connected graph means that at least one side of any square overlaps with another square, and any two squares are connected directly or indirectly…
Can you help them?
Input
The first line contains a integer T — the number of cases.
For each case, an integer n is given as described above.
1 <= T <= 100000
1 <= n <= 1000000000
Output
For each case, output the longest perimeter and the smallest perimeter.
Sample Input 1
5
1
2
3
4
5
Sample Output 1
Case #1: 4 4
Case #2: 6 6
Case #3: 8 8
Case #4: 10 8
Case #5: 12 10
Source
Takio
题意:给你n个11的小方块拼成一个图形,求能拼出的图形最小周长和最大周长
做法:
想要周长大那么就需要尽量减少边和边重合
最大周长明显是排成一列,那么就是2n+2
最小周长可以这样考虑
假如n是一个完全平方数 那么最小周长肯定是拼成正方形的时候
也就是长和宽的差尽量小
考虑从正方形往外拓展
在正方形外放了第一个方块之后(周长+2)
这条边再添加方块是不再增加周长的(添加在红色这一排)
在正方形的边全部添加过方块后 再从另一条边添加(周长+2)
跟第一次同理
代码:
int t;
cin>>t;
for(int cas=1;cas<=t;++cas) {
printf("Case #%d: ",cas);
int n;
cin>>n;
int m = sqrt(n+0.5);//消除误差
int a = 2*n+2;
int b;
if(m*m==n)b = 4*m;
else if(m*m+m>=n)b = 4*m+2;
else b = 4*m+4;
printf("%d %d\n",a,b);
}
C
Let’s go
Description
Go is a game of territory.There are two color of stones in Go, black and white.
Two location are adjacent in the chess board if the Manhattan distance between them equals 1.
Two stones are called connected if they are adjacent and share the same color.
A stone is always connected to itself.
The connection between stones are compliant with transitivity, which means if A is conencted to B and B is connected to C, then A is connected to C.
A group of connected stones, are called a block if all the stones inside it are connected, and there is no stones outside it connected to any stones inside it.
The number of empty locations (no stone on this location) adjacent to all the stones of a block is called the liberty of this block.
When a stone is placed, if there is any opposite color block’s liberty equals 0, remove all the stone of that block from the chess board.
In this question, you will be given the order and locations of stones in a go match.
Please output the final situation on the chess board. The chess board is always with 9 x 9 size.
Black and white will strictly plays turn by turn and the black will alway goes the first.
Input
There are serveral test cases.
The first line of a test case contains one number N, indicating the total turns in a game.
Followed by N lines, each line contains two integers, x and y ( 1 <= x, y <=9 ), indicating the location of the stone.
An N equals -1 means the end of input and you should not proceed that case.
Output
For each case, output a 10 x 10 map of characters for the final situation on the chess board, with a Y axis on the left most column and an X axis on the bottom column.
Using ‘B’ for black stones, ‘W’ for white stones and ‘.’ for empty locations. Please be aware that the LEFT-BOTTOM character of the map is an space.
See sample input and output for more details.
Sample Input 1
10
2 1
1 2
2 2
3 2
1 3
2 3
1 1
3 1
3 3
1 2
-1
Sample Output 1
9…
8…
7…
6…
5…
4…
3BWB…
2W.W…
1…W…
123456789
Source
scau_acm
题意:让你模拟一个围棋游戏,会有吃子的操作
做法:用dfs来检查对手棋子的气和除去对方的棋子
代码:
int a[12][12];//棋子 -1为空,0为白,1为黑
bool vis[12][12];
int dx[] = {0,-1,0,1},dy[] = {1,0,-1,0};//位移
bool judge(int x,int y) {//检查是否在棋盘内
return 1<=x&&x<=9&&1<=y&&y<=9;
}
bool dfs(int x,int y) { //检查这块棋子是否有气
vis[x][y] = 1;
for(int i=0; i<4; ++i) {
int nx = x + dx[i] ,ny = y + dy[i];//检查相邻棋子
if(vis[nx][ny])continue;
if(judge(nx,ny)&&a[nx][ny]==-1)return 1;
if(judge(nx,ny)&&a[nx][ny]==a[x][y]) {
if(dfs(nx,ny))return 1;
}
}
return 0;
}
void del(int x,int y) { //删除棋子
vis[x][y] = 1;
for(int i=0;i<4;++i)
{
int nx = x + dx[i] ,ny = y + dy[i];//检查相邻棋子
if(vis[nx][ny])continue;
if(judge(nx,ny)&&a[nx][ny]==a[x][y])del(nx,ny);
}
a[x][y] = -1;
}
void check(int x,int y) {//检查落子的周围
for(int i=0; i<4; ++i) {
int nx = x+dx[i],ny = y + dy[i];
if(judge(nx,ny)&&a[nx][ny]==1-a[x][y]) {
memset(vis,0,sizeof vis);
bool liber = dfs(nx,ny);
if(liber==0) {
memset(vis,0,sizeof vis);
del(nx,ny);
}
}
}
}
int main() {
int n;
while(cin>>n)
{
if(n==-1)break;
memset(a,-1,sizeof a);
int now = 1;
for(int i=1;i<=n;++i)
{
int x,y;
cin>>x>>y;
a[x][y] = now;
now = 1-now;
check(x,y);
}
for(int j=9;j>=1;--j)
{
printf("%d",j);
for(int i=1;i<=9;++i)
{
if(a[i][j]==-1)putchar('.');
else if(a[i][j]==0)putchar('W');
else putchar('B');
}
puts("");
}
puts(" 123456789");
}
return 0;
}
D
Lock
Description
Yplusplus has a rotary password lock. The lock has n(n <= 50000) positions and each position corresponds to a number from 0 to 3. This is a rotating lock, so digits of each position are circular which means that 0 can become 1 or 3 with one rotation. In the same way, 3 can become 0 or 2 with one rotation. In addition, this lock is a bit rusty, so some positions can not be rotated.The condition to open the lock is to rotate some positions so that it contains k(1<=k<=8) non-overlapping, consecutive specified password strings.Now, Yplusplus wants to open the lock with as few rotations as possible. So he turns to you. If the lock can not be open, output -1.
Input
The first line contains a integer T — the number of cases.For each case, the first line contains two integers n and k — the length of lock and the number of specified password strings.The following line represents the current state of lock.Next line represents the rusty state of lock, 0 means the coresponding position is not rusty and 1 meas it is rusty.The next k lines represent each password string.See samples for more details.
Output
Print a single integer for each case — the fewest rotations to open the lock. If it is impossible, print -1.
Sample Input 1
2
6 2
012321
000000
10
12
6 2
022332
110000
10
13
Sample Output 1
2
5
Hint
for the first sample, change 012321 to 012310.for the second sample, change 022332 to 021013.
Source
yplusplus
(这道题是最难的 没有基础的同学建议跳过)
题意:有一个数字有0-3的密码锁,打开他需要把密码锁扭到包含k个给定的密码串的状态,并且这些密码串在密码锁上没有重叠。求最小操作次数。
做法:
先计算每个密码串在每个位置匹配的代价
因为数字只有0-3 把每个数字分开来算代价加到同一个密码串上
算代价对密码串的顺序反过来构造一个多项式
那么一个位置匹配的代价就是对应后面第len个位置系数
得到代价之后做一个简单的状压dp
代码:
struct cpx {
double x,y;
cpx() {}
cpx(double _x ,double _y) {
x = _x;
y = _y;
}
cpx operator - (const cpx &b)const {
return cpx(x-b.x,y-b.y);
}
cpx operator + (const cpx &b)const {
return cpx(x+b.x,y+b.y);
}
cpx operator * (const cpx &b)const {
return cpx(x*b.x - y*b.y,x*b.y+y*b.x);
}
};
cpx d[1111111],f[1111111];
void change(cpx y[],int len) {
int i,j,k;
for(i = 1,j=len/2; i<len-1; ++i) {
if(i<j)swap(y[i],y[j]);
k = len/2;
while(j>=k) {
j -= k;
k /= 2;
}
if(j<k)j+=k;
}
}
void fft(cpx y[],int len,int on) {
change(y,len);
for(int h = 2; h<=len; h<<=1) {
cpx wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
for(int j = 0; j<len; j+=h) {
cpx w(1,0);
for(int k=j; k<j+h/2; ++k) {
cpx u = y[k];
cpx t = w*y[k+h/2];
y[k] = u + t;
y[k+h/2] = u - t;
w = w*wn;
}
}
}
if(on==-1) {
for(int i=0; i<len; ++i)y[i].x /=len;
}
}
string lock;
string rust;
string pass[10];
int len[10];
int dp[50020][555];
int w[50020][10];
int n,k;
void calw() {
memset(w,0,sizeof w);
int len1 = 1;//fft length
while(len1<2*n)len1<<=1;
for(int p=0; p<k; ++p) {
for(int i=0; i<=3; ++i) {
int len2 = len[p];//oassword length
for(int j=0; j<n; ++j) {
if(lock[j]-'0'==i)d[j] = cpx(0,0);
else {
if(rust[j]-'0')d[j] = cpx(inf,0);
else {
int x = lock[j] - '0';
int c = min((x - i + 4)%4,(i - x +4 )%4 );
d[j] = cpx(c,0);
}
}
}
for(int j=n;j<len1;++j)d[j] = cpx(0,0);
for(int j=0;j<len2;++j)f[len2-j-1] = cpx(((pass[p][j]-'0')==i),0);
for(int j = len2;j<len1;++j)f[j] = cpx(0,0);
fft(d,len1,1);
fft(f,len1,1);
for(int j =0;j<len1;++j)d[j] = d[j]*f[j];
fft(d,len1,-1);
for(int j=0;j<n;++j)
{
w[j][p] += (int)(d[j+len2-1].x + 0.5);
}
}
}
}
int caldp()
{
memset(dp,0x3f,sizeof dp);
dp[0][0] = 0;
int sz = 1<<k;
for(int i=0;i<n;++i)
{
for(int j=0;j<sz;++j)
{
if(dp[i][j]==inf)continue;
dp[i+1][j] = min(dp[i+1][j],dp[i][j]);
for(int l=0;l<k;++l)
{
if((j>>l)&1)continue;
if(w[i][l]>=inf)continue;
int len2 = len[l];
if(len2+i>n)continue;
int nt = j|(1<<l);
dp[i+len2][nt] = min(dp[i+len2][nt],dp[i][j] + w[i][l]);
}
}
}
int ans = inf;
for(int i=0;i<=n;++i)
ans = min(ans,dp[i][sz-1]);
return ans;
}
int main() {
int t;
sd(t);
while(t--) {
// int n,k;
sdd(n,k);
cin>>lock>>rust;
int tot = 0;
for(int i=0;i<k;++i)cin>>pass[i],len[i] = pass[i].length(),tot += len[i];
if(tot>n) {
puts("-1");
continue;
}
calw();
int ans = caldp();
if(ans==inf)ans = -1;
printf("%d\n",ans);
}
return 0;
}
E
Effective Conversation
Description
Most Chinese now use WeChat to communicate. Recently, Ly joined some group chats with a lot of top programmers. To learn from them, Ly needs to find some effective conversations in the group chats.
In a group of n individuals, people are numbered 1 to n. Now that Ly has a conversation that contains m sentences, the ith sentence is said by person numbered ai.
An effective conversation should be some consequent sentences in a conversion, which includes exactly k different people, and the exchange round should be no less than t rounds(1-2-2 means 1 round, 1-2-2-3 means 2 rounds).
You need to help Ly find the longest effective conversation.
Input
The first line contains a integer T — the number of cases.
For each case, the first line contains four integers n, k, t, m,meaning as described above.
The second line contains m integer ai, means that the ith sentence was said by person numbered ai.
3 <= n <= 500
1 <= k <= n
1 <= t <= m <= 100000
Output
Output an integer, represent the length of the longest effective conversation.
Sample Input 1
2
4 2 3 7
1 1 2 3 4 3 4
7 4 3 13
5 2 1 1 2 2 7 3 7 7 3 4 6
Sample Output 1
4
10
Source
Ly
题意:给出一段长为m的对话顺序,出现的人的编号是1-n。定义一段好对话为出现的人刚好为k个,并且交换说话的次数>=t次。求好对话的最大长度。
做法:可以考虑到对于每个左端点L,都有一个对应的最大右端点使得这一段的对话能满足好对话条件。所以用尺取做,定住左端点,右端点尽量往右移动,不能移动再把左端点往右移缩短区间。
代码:
int ch[123456];//交换对话的前缀和
int a[123456];
int times[555];//每个人的出现次数
int main() {
#ifdef LOCAL
int t;
cin>>t;
while(t--)
{
int n,k,t,m;
cin>>n>>k>>t>>m;
for(int i=1;i<=m;++i)
{
cin>>a[i];
ch[i] = ch[i-1];
if(i>1&&a[i]!=a[i-1])++ch[i];
}
for(int i=1;i<=n;++i)times[i] = 0;
int l = 1,r = 0;
int cnt = 0;//当前区间的人数
int ans = 0;
while(r<m)
{
while(cnt<k)
{
if(r==m)break;
int x = a[++r];
if(times[x]==0)++cnt;
++times[x];
}
while(cnt==k)
{
int change = ch[r] - ch[l];
if(change>=t)ans = max(ans,r-l+1);
if(r==m)break;
int x = a[++r];
if(times[x]==0)++cnt;
++times[x];
}
while(cnt>k)
{
if(l==r)break;
int x = a[l++];
if(times[x]==1)--cnt;
--times[x];
}
}
printf("%d\n",ans);
}
return 0;
}
F
Atelier Lydie & Soeur ~ Hmmm…what shall we craft next?
Description
The twins Lydie and Suelle live in a small atelier without much of a reputation in Melveille, the capital of Adalett. They help their alchemist father and they one day hope to run the kingdom’s top atelier.
Today they are still crafting items through alchemy. Crafting an item they need to spend some materials, and fix them on a painting. Now they have a drawing with the size of 2 * n, and m materials. The size of i-th material is xi * yi, and its weight is wi. They need to put these materials on painting horizontally or vertically,and they can’t not overlap, so that the sum of the weights of these materials is maximum.
As their rank get higher and higher, the conditions for them to upgrade are getting harder and harder. They want to seek some help. Originally they would like to ask their teacher Ilmeria Von Leinweber. But she is now traveling in the painting world with Firis and sophie. Can you give them some help?
Input
The first line contains a integer T — the number of cases.
For each case, the first line contains two integers m and n, represents the number of materials and the length of the painting.
In the following m lines , each line consists of three posivie integers xi, yi. wi, represents the size and weight of the i-th material.
1 <= T <= 10
1 <= m,n <= 100
1 <= xi <= 2
1 <= yi <= 100
1 <= wi <= 100000
Output
The output contains T lines, each line contains the answer of the i-th case.
Sample Input 1
2
4 3
2 2 1
1 1 1
1 1 1
1 1 1
4 3
2 1 1
1 1 1
1 1 1
1 1 1
Sample Output 1
Case #1: 3
Case #2: 4
题意:有一块长为n宽为2的画,给你m个长为yi宽为xi 权值为wi的材料,把这些材料放在画上并且没有地方重复覆盖,方向任意。求画上能放的材料的最大权值。
做法:因为格子只有2行,所以做一个dp,用dp[i][j]表示第一行使用了i格第二行使用了j格状态下的最大权值。需要注意的是材料还可以换一个方向放。
代码:
(dp是用滚动数组的写法)
int dp[2][111][111];
int x[111],y[111],w[111];
int main() {
int t;
cin>>t;
for(int cas = 1; cas<=t; ++cas) {
printf("Case #%d: ",cas);
int m,n;
cin>>m>>n;
memset(dp,0,sizeof dp);
for(int i=1; i<=m; ++i)cin>>x[i]>>y[i]>>w[i];
int o = 0;
int ans = 0;
for(int i=1; i<=m; ++i) {
int nt = o^1;
memset(dp[nt],0,sizeof dp[nt]);
for(int j=0; j<=n; ++j)
for(int k=0; k<=n; ++k)
dp[nt][j][k] = dp[o][j][k];
if(x[i]==1) {
for(int j=0; j<=n; ++j)
for(int k=0; k<=n; ++k) {
if(j>=y[i])dp[nt][j][k] = max(dp[nt][j][k],dp[o][j-y[i]][k] + w[i]);
if(k>=y[i])dp[nt][j][k] = max(dp[nt][j][k],dp[o][j][k-y[i]] + w[i]);
ans = max(ans,dp[nt][j][k]);
}
} else if(x[i]==2) {
for(int j=0; j<=n; ++j)
for(int k=0; k<=n; ++k) {
if(j>=y[i]&&k>=y[i])dp[nt][j][k] = max(dp[nt][j][k],dp[o][j-y[i]][k-y[i]] + w[i]);
ans = max(ans,dp[nt][j][k]);
}
}
swap(x[i],y[i]);
if(x[i]==1) {//跟上面一样 直接复制的
for(int j=0; j<=n; ++j)
for(int k=0; k<=n; ++k) {
if(j>=y[i])dp[nt][j][k] = max(dp[nt][j][k],dp[o][j-y[i]][k] + w[i]);
if(k>=y[i])dp[nt][j][k] = max(dp[nt][j][k],dp[o][j][k-y[i]] + w[i]);
ans = max(ans,dp[nt][j][k]);
}
} else if(x[i]==2) {
for(int j=0; j<=n; ++j)
for(int k=0; k<=n; ++k) {
if(j>=y[i]&&k>=y[i])dp[nt][j][k] = max(dp[nt][j][k],dp[o][j-y[i]][k-y[i]] + w[i]);
ans = max(ans,dp[nt][j][k]);
}
}
o^=1;
}
printf("%d\n",ans);
}
return 0;
}
G
Atelier Lydie & Suelle ~ Traveling in the unknown mysterious world
Description
Lydie and Suelle are twin sisters, who are also alchemists, living in Merveille, the capital of Kingdom of Adalet, and they aim to make their atelier the best atelier in the kingdom. They are hardworking, but don’t get a lot of business and survive on a bare minimum. This environment makes the bonds between the two stronger. One day when synthesizing, they hear a voice from the basement their father has forbidden them from entering, where they discover a painting that brings them closer to achieving their dream. This painting contains a different world full of unique materials.
Today they also traveled to various painting worlds. However, this world is not the same as the past. The world is complicated and weird. The scenes they all see are the same, and the structure of the world is recursive. So that they are lost in this world.
This world can be represented by a two-dimensional graphic. The initial graph is as follows, which is a 3 * 3 graph and contains eight 'x’s and one ‘_’.
xxx
x_x
xxx
Then each time this graph is recursively constructed, the current graph will continue to be substituted into the initial graph as an ‘x’. And use ‘’ to spread the middle ‘’. The next construction of the graph is as follows, which is a 9 9 graph and contains 8 8 'x’s and 9 9 - 8 8 '_'s.
xxxxxxxxx
x_xx_xx_x
xxxxxxxxx
xxx___xxx
x_x___x_x
xxx___xxx
xxxxxxxxx
x_xx_xx_x
xxxxxxxxx
In the i-th construction, the world contains 8^i 'x’s and (9^i - 8^i) ‘_’, where ‘^’ means the power. After a long period of time, this world has done infinity recursive constructions.
Now that the twins are trying to figure out the structure of the world, they want to know how much ‘x’ is contained in the matrix formed by [x1, y1] to [x2, y2]. [x1, y1] and [x2, y2] represent the upper left and lower right corners of this matrix. And the coordinates of the top left corner of this world is [1, 1]
But this is too difficult for them. Can you help them solve this problem?
Input
The first line contains a integer T — the number of cases.
For each case, contains four integers x1, y1, x2, y2 in one line, represents the upper left and lower right corners of this matrix.
1 <= T <= 1000
1 <= x1 <= x2 <= 1000000000
1 <= y1 <= y2 <= 1000000000
Output
The output contains T lines, each line contains the answer of the i-th case.
Sample Input 1
10
1 1 1 1
1 1 2 2
1 1 3 3
1 1 4 4
1 1 5 5
1 1 6 6
1 1 7 7
1 1 8 8
1 1 9 9
1 1 10 10
Sample Output 1
Case #1: 1
Case #2: 3
Case #3: 8
Case #4: 14
Case #5: 18
Case #6: 24
Case #7: 37
Case #8: 47
Case #9: 64
Case #10: 82
题意:给出一个只有 ’ x ’ 和 ’ _ ’ 两种字符的图的规律,让你求一个左上角为(x1,y1)右下角为(x2,y2)的矩形中x的个数。
做法:
先将问题容斥转为求(1,1),(x,y)矩形中的x个数
明显这个图形是按一个规律重复构造的,那么就用dfs求。
不难发现一个边长为3k的图可以分为9个边长为3(k-1)的小块,并且中间是空的
对于每个边长为3k的块,有的x的个数为8k
所以先预处理每个大小的块有的x的个数
然后递归运算
先算出左上角开始拥有的完整的一部分小块
然后算出这些小块正下方和正右方没算到的
再计算右下角的剩余部分
代码:
long long had[33];
long long dfs(int u,int r,int c,long long edge)
{
if(r<=0||c<=0)return 0;
long long ed = edge/3;
int a = r/ed;
int b = c/ed;
int tot = a*b;
if(tot>=4)--tot;
long long res = 0;
res += tot*had[u-1];
// 增加正方形右侧多出的部分
if(b==1&&a>=2)res += dfs(u-1,ed,c-b*ed,edge/3)*(a-1);//覆盖到中间的空块
else res += dfs(u-1,ed,c-b*ed,edge/3)*a;
// 增加正方形下侧多出的部分
if(a==1&&b>=2)res += dfs(u-1,r - a*ed,ed,edge/3)*(b-1);
else res += dfs(u-1,r - a*ed,ed,edge/3)*b;
// 增加正方形右下角的部分 需要排除命中中间块的情况
if(r-a*ed>0&&c-b*ed>0&&(a!=1||b!=1))res += dfs(u-1,r-a*ed,c-b*ed,edge/3);
return res;
}
long long cal(int r,int c)
{
int mx = max(r,c);
int id = 1;
long long edge = 3;
while(edge<mx)
{
edge*=3;
++id;
}
return dfs(id,r,c,edge);
}
int main() {
had[0] = 1;
for(int i=1;i<=20;++i)had[i] = had[i-1]*8;
int t;
cin>>t;
for(int cas = 1; cas<=t; ++cas) {
printf("Case #%d: ",cas);
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
long long ans = cal(x2,y2) - cal(x2,y1-1) - cal(x1-1,y2) +cal(x1-1,y1-1);
printf("%lld\n",ans);
}
return 0;
}
H
Treasure
Description
Li likes playing games. One of games names Finding Treasure. In the game, you have given a map (N*M). The coordinate坐标 (1,1) is the start position and (N , M) is the Treasure. There are monsters, walls, and grasslands in the map. A player can walk on grasslands, but not walls. In a map, a player can move up, down, left or right one step one block. The monsters can’t move, but they can fight against the player if a player meet one of them. Then, one of two results will happen. If the level of the player is greater or equal than the level of the monster. The player lives. Otherwise, the player dies. Of cause, no player want die. So, a player can train himself before starting his adventure. The question is : Given all the information of a map, what’s the minimal level a player need to get the treasure ,and the minimal steps?
Input
The first line has two integers, means N(row, 0 < N < = 50) and M(column, 0 < M < = 50)Then, following N lines. Each line contains M integer numbers. -1 represents a wall, 0 represents a grassland, X(0< X < 1 e9) represents a monster(X is the level of the monster)TIPS: It is possible that there is a monster on (1, 1) or (N, M).
Output
Each of two lines has a integer, first is the minimal level, second is the minimal steps. If can’t get the treasure, output only 1 line – “nothing”
Sample Input 1
3 4
1 -1 1 2
0 2 0 6
0 9 8 1
Sample Output 1
6
5
Hint
TIPS: (1, 1)-(2, 1)-(2, 2)-(2, 3)-(2, 4)-(3, 4)
题意:给一个地图,-1代表墙,0为草地,大于0的数x代表有一个x级的怪物,跟这个怪物战斗只要等级>=x就可以活下来。现在问你能从(1,1)到(n,m)的最小等级以及此时的最少步数。
做法:最短路问题。先求从(1,1)到每个格子的最小等级,然后算从(1,1)到(n,m)对应等级下的最短路。
代码:(用的是dijkstra算法)
int dx[] = {1,0,-1,0},dy[] = {0,1,0,-1};
int n,m;
int dis[111][111];
int a[111][111];
bool vis[111][111];
bool judge(int x,int y) {
return 1<=x&&x<=n&&1<=y&&y<=m&&a[x][y]!=-1;
}
int callevel() {
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
priority_queue<pair<int,pair<int,int> > > q;
q.push(make_pair(-a[1][1],make_pair(1,1)));
dis[1][1] = a[1][1];
while(!q.empty()) {
pair<int,pair<int,int> > p = q.top();
q.pop();
int x = p.second.first;
int y = p.second.second;
if(vis[x][y])continue;
vis[x][y] = 1;
int dist = -p.first;
if(x==n&&y==m)return dist;
for(int i=0; i<4; ++i) {
int nx = dx[i] + x,ny = dy[i] + y;
if(judge(nx,ny)) {
int lev = max(dist,a[nx][ny]);
if(lev<dis[nx][ny]) {
dis[nx][ny] = lev;
q.push(make_pair(-lev,make_pair(nx,ny)));
}
}
}
}
return -1;
}
int calmindist(int lev) {
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
priority_queue<pair<int,pair<int,int> > > q;
q.push(make_pair(-0,make_pair(1,1)));
dis[1][1] = 0;
while(!q.empty()) {
pair<int,pair<int,int> > p = q.top();
q.pop();
int x = p.second.first;
int y = p.second.second;
if(vis[x][y])continue;
vis[x][y] = 1;
int dist = -p.first;
if(x==n&&y==m)return dist;
for(int i=0; i<4; ++i) {
int nx = dx[i] + x,ny = dy[i] + y;
if(judge(nx,ny)&&dis[nx][ny]>dis[x][y] + 1&&a[nx][ny]<=lev) {
dis[nx][ny] = dis[x][y] + 1;
q.push(make_pair(-dis[nx][ny],make_pair(nx,ny)));
}
}
}
return -1;
}
int main() {
while(cin>>n>>m) {
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j)
cin>>a[i][j];
if(a[1][1]==-1||a[n][m]==-1) {
puts("nothing");
continue;
}
int lev = callevel();
if(lev==-1) {
puts("nothing");
continue;
}
int step = calmindist(lev);
printf("%d\n%d\n",lev,step);
}
return 0;
}
I
Alice and Bob are drawing lines
Description
Alice and Bob are drawing lines on a two-dimensional coordinate system.
Alice always draws vertical segments while Bob draws horizontal ones.
Now, you may think that this problem is about a game.
But in fact they are just drawing a picture.
Please output a character map representing the picture, the square area from (-10, -10) to (10, 10) on the coordinate system.
See input and output description for more details.
Input
There are serveral test cases.
The first line of each case contains a integer N (N <= 1000), indicating the there are N lines on the plane. An N equals -1 means the end of the input and you don’t need to output that case.
Then followed by N lines, each line contains four integers, x1, y1, x2, y2, indicating two end point of the line. ( -1e9 <= x1, y1, x2, y2 <= 1e9, and (x1, y1) must be distinct from (x2, y2) )
The lines are guaranteed to be horizontal or vertical.
Output
Output a 22 x 22 character picture.
The x axis is always on the twelfth row with a ‘>’ on the right.
The y axis is always on the eleventh column with a ‘^’ on the top.
The ‘-’ indicates that a line goes across or ends at this point horizontally, while a ‘|’ means vertically.
Specially, when both the two situations happen on a same point, we use a ‘+’.
Please be aware that the top row and the right most column should only contains ‘^’ or ‘>’. And the output picture should not contain tailing spaces.
Sample Input 1
11
-8 -4 -8 4
-8 4 -5 4
-5 4 -5 -4
-8 0 -5 -0
2 4 -2 4
-2 4 -2 -4
-2 -4 2 -4
4 -4 4 4
4 4 10 4
10 4 10 -4
7 4 7 -4
-1
Sample Output 1
^
|
|
|
|
|
|
+--+ +-+-- +--+--+
| | | | | | |
| | | | | | |
| | | | | | |
--+--+--+-+---+--+--+>
| | | | | | |
| | | | | | |
| | | | | | |
| | +-+-- | | |
|
|
|
|
|
|
Source
scau_acm
题意:A和B画线,输出坐标系小范围内的图。
做法:直接模拟,用数组记录这个位置有没有横线或竖线,需要注意后面不能有多余空格。
代码:(因为坐标有负数所以保存在数组中时全部都+20)
bool row[88][88],col[88][88];
int main() {
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif // LOCAL
int n;
while(cin>>n)
{
if(n==-1)break;
memset(row,0,sizeof row);
memset(col,0,sizeof col);
for(int i=-10;i<=10;++i)row[i+20][0+20] = 1,col[0+20][i+20] = 1;
while(n--)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
if(x1==x2&&x1>=-10&&x1<=10)
{
if(y1>y2)swap(y1,y2);
y1 = max(y1,-10);
y2 = min(y2,10);
for(int i=y1;i<=y2;++i)col[x1+20][i+20] = 1;
}
else if(y1==y2&&y1>=-10&&y1<=10)
{
if(x1>x2)swap(x1,x2);
x1 = max(x1,-10);
x2 = min(x2,10);
for(int i=x1;i<=x2;++i)row[i+20][y1+20] = 1;
}
}
puts(" ^");
for(int i=10;i>=-10;--i)
{
int y = i + 20;
for(int j=10;j>=-10;--j)
{
if(row[j+20][y]||col[j+20][y])
{
for(int k=-10;k<=j;++k)
{
int x = k+ 20;
if(row[x][y]&&col[x][y])putchar('+');
else if(row[x][y])putchar('-');
else if(col[x][y])putchar('|');
else putchar(' ');
}
break;
}
}
if(i==0)putchar('>');
puts("");
}
}
return 0;
}