湖南多校对抗赛(2015.4.6)CSU 1561~1569 题解

A:点击打开链接

CSU 1561 (More)Multiplication

题意:把两个数的乘积每个位置的结果填充上去。

注意这个矩阵最大是1e8,所以不能开数组。

模拟题

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 10005;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
int ans[N * 2];
char A[N], B[N];
char a[N * 4];
int main() {
	while (~scanf("%s %s", A, B)) {
		int m = strlen(A), n = strlen(B), x = 0, y = 0;
		for (int i = 0; i < m; i++) {
			x = x * 10 + (A[i] - '0');
		}
		for (int i = 0; i < n; i++) {
			y = y * 10 + (B[i] - '0');
		}
		if (x == 0 && y == 0) break;
		int num = x*y, size = 0;
		while (num > 0) {
			ans[size++] = num % 10;
			num /= 10;
		}
		while (size < n + m) {
			ans[size++] = -1;
		}
		n = n * 4 + 5;
		m = m * 4 + 5;
		bool f = false;
		for (int ii = 0; ii < n; ii++) {
			a[m] = '\0';
			for (int jj = 0; jj < m; jj++) a[jj] = ' ';
			if (ii == 0 || ii == n - 1) {
				a[0] = a[m - 1] = '+';
				for (int jj = 1; jj < m - 1; jj++) {
					a[jj] = '-';
				}
			}
			else {
				a[0] = a[m - 1] = '|';
				if (ii == 1) {
					for (int j = 4; j < m - 1; j += 4) {
						a[j] = A[j / 4 - 1];
					}
				}
				else if (ii == n - 2) {
					for (int pos = m - 6, id = 0; pos > 0; pos -= 4, id++) {
						a[pos] = ans[id] + '0';
						a[pos - 2] = '/';
					}
					if (!f) a[1] = ' ';
				}
				else {

					if ((ii - 2) % 4 == 0) {
						for (int j = 2; j < m - 2; j++) {
							if ((j - 2) % 4 == 0) a[j] = '+';
							else a[j] = '-';
						}

					}
					else {
						for (int j = 2; j < m - 2; j += 4) {
							a[j] = '|';
						}
						if ((ii + 1) % 4 == 0) {
							if (f) a[1] = '/';
							for (int j = 4; j < m - 1; j += 4) {
								a[j + 1] = '/';
								a[j - 1] = (A[j / 4 - 1] - '0') * (B[(ii + 1) / 4 - 1] - '0') / 10 + '0';
							}
						}
						if (ii % 4 == 0) {
							for (int j = 4; j < m - 1; j += 4) {
								a[j] = '/';
							}
							a[m - 2] = B[ii / 4 - 1];
						}
						if ((ii - 1) % 4 == 0) {
							if (ans[size - 1] != -1) {
								a[1] = ans[size - 1] + '0';
								f = true;
							}
							size--;

							for (int j = 4; j < m - 1; j += 4) {
								a[j - 1] = '/';
								a[j + 1] = (A[j / 4 - 1] - '0') * (B[(ii - 1) / 4 - 1] - '0') % 10 + '0';
							}
						}
					}
				}
			}
			printf("%s\n", a);
		}
	}

	return 0;
}
B: 点击打开链接
CSU 1562 Fun House

题意:

给定一个矩阵,矩阵内部有2种镜子/ \,从边缘的*入射一条光线,则光线一定会射到边缘,把边缘用&标记。

然后输出这个矩阵。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>

using namespace std;

const int MAX_N = 27;

int n, m;
int ex, ey;

char maz[27][27];
bool vis[MAX_N][MAX_N];
bool found;

bool safe(int x, int y) {
	return x >= 0 && x < m && y >= 0 && y < n;
}

void dfs(int x, int y, int dir) {
	if (found) return ;
	if (dir == 1) ++x;
	else if (dir == 2) ++y;
	else if (dir == 3) --x;
	else --y;
	if (safe(x, y)) {
		if (maz[x][y] == 'x') {
			ex = x, ey = y;
			found = true;
			return ;
		}
		if (maz[x][y] == '.') dfs(x, y, dir);
		else if (maz[x][y] == '/') {
			if (dir == 1) {
				dfs(x, y, 4);
			} else if (dir == 2) {
				dfs(x, y, 3);
			} else if (dir == 3) {
				dfs(x, y, 2);
			} else {
				dfs(x, y, 1);
			}
		} else {
			if (dir == 1) {
				dfs(x, y, 2);
			} else if (dir == 2) {
				dfs(x, y, 1);
			} else if (dir == 3) {
				dfs(x, y, 4);
			} else {
				dfs(x, y, 3);
			}
		}
	}
}

void Clear() {
	ex = 0, ey = 0;
	found = false;
	memset(maz, 0, sizeof maz);
}

int main() {
	int cas = 0;
	while (2 == scanf("%d%d", &n, &m)) {
		if (0 == n && 0 == m) break;
		int sx = 0, sy = 0;
		Clear();
		for (int i = 0; i < m; ++i) {
			scanf("%s", maz[i]);
			for (int j = 0; j < n; ++j) {
				if (maz[i][j] == '*') {
					sx = i, sy = j;
					maz[i][j] = '.';
				}
			}
		}
		if (sx == 0)
			dfs(sx, sy, 1);
		else if (sx == m-1)
			dfs(sx, sy, 3);
		else if (sy == 0)
			dfs(sx, sy, 2);
		else
			dfs(sx, sy, 4);
		printf("HOUSE %d\n", ++cas);
		for (int i = 0; i < m; ++i) {
			for (int j = 0; j < n; ++j) {
				if (i == sx && j == sy) {
					putchar('*');
				} else if (i == ex && j == ey) {
					putchar('&');
				} else putchar(maz[i][j]);
			}
			puts("");
		}
	}
    return 0;
}
C: 点击打开链接
题意:

给定一个字符串,问字典序第k小的是什么。

从高位到低位枚举,每次填充排列数<=k且最大的那个字母。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>

using namespace std;
typedef long long ll;
const int N = 20;
char s[N], t[N];
ll k;
ll num[27];
ll J[30];
int len;
ll way(){
	ll sum = 0;
	for(int i = 0; i < 26; i++)sum += num[i];
	ll ans = J[sum];
	for(int i= 0; i < 26; i++)ans /= J[num[i]];
	return ans;
}
void dfs(int now , ll pre){
	if(now == len)return ;
	char c = 'A';
	for(int i = 0; i < 26; i++){
		if(num[i]==0)continue;
		c = 'A'+i;
		num[i]--;
		ll hehe = way();
		num[i]++;
		if(pre + hehe >= k){
			break;
		}
		pre += hehe;
	}
	num[c-'A']--;
	t[now] = c;
	dfs(now+1, pre);
}
int main() {
	J[0] = 1;
	for(ll i = 1; i < 30; i++)J[i] = J[i-1]*i;
	while (~scanf("%s", s)) {
		cin>>k;
		if(s[0] == '#' && k==0)break;
		memset(num, 0, sizeof num);
		len = strlen(s);
		memset(t, 0, sizeof t);
		for(int i = 0; s[i]; i++)num[s[i]-'A'] ++;
		dfs(0, 0);
		puts(t);
	}
	return 0;
}

E: 点击打开链接

CSU 1565 Word Cloud

某模拟题。

给出矩阵的宽度为P, N个字母。

下面给出每个字母和它的高度。

用题目中的图求出这个字母的宽度。

把字母从上到下,从左到右依次填充进矩阵,问填充完后矩阵的高度是多少

注意字母间距离是 10px

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int MAX_N = 107;

int w, n;
char str[100007];
int c[MAX_N], len[MAX_N];
int H[MAX_N], W[MAX_N];

int main() {
	int cas = 0;
	while (2 == scanf("%d%d", &w, &n)) {
		if (0 == w && 0 == n) break;
		int Cmax = 0;
		for (int i = 0; i < n; ++i) {
			scanf("%s%d", str, &c[i]);
			Cmax = max(Cmax, c[i]);
			len[i] = strlen(str);
		}
		for (int i = 0; i < n; ++i) {
			H[i] = 8 + ceil(40 * (c[i] - 4) * 1. / (Cmax - 4));
			W[i] = ceil(9. * len[i] * H[i] / 16);
		}
		long long ans = 0, sum = 0;
		bool row = false;
		int maxH = 0;
		w += 10;
		for (int i = 0; i < n; ++i) {
			if (row) {
				row = false;
				ans += maxH;
				sum = 0;
				maxH = 0;
			}
			if (sum + W[i] + 10 <= w) {
				maxH = max(maxH, H[i]);
				sum += W[i] + 10;
			} else row = true, --i;
		}
		if (sum != 0) ans += maxH;
		printf("CLOUD %d: %lld\n", ++cas, ans);
	}
    return 0;
}
F: 点击打开链接
CSU 1566 The Maze Makers

给定一个迷宫的图,每个格子有16种形态,用一个16进制数表示。

边缘有且仅有2个缺口。

问:

if 2个缺口不连通则输出"No solution"

else if 存在点是不可达的则输出“Unreachable cell"

else if 2个缺口间存在不同的路径则输出 "Multiple path" 

else "Maze ok"


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 55;
int n, m;
vector<int>G[N*N], path;
vector<pii>D;
int has(int x, int y){return x*m+y;}
void add(int x, int y, int i, int j){
	G[has(x,y)].push_back(has(i,j));
}
int getx(int val){return val/m;}
int gety(int val){return val%m;}
bool inmap(int x, int y){
	return 0<=x && x < n && 0<=y&&y<m;
}
char s[N];
int mp[N][N];
int step[4][2] = {0,-1, 1,0, 0,1, -1,0};
bool vis[N][N];
void bfs(int x, int y){
	memset(vis, 0, sizeof vis);
	queue<int>q;
	q.push(has(x,y));
	vis[x][y] = true;
	while(!q.empty()){
		int u = q.front(); q.pop();
		for(int i = 0; i < G[u].size(); i++){
			int v = G[u][i];
			x = getx(v); y = gety(v);
			if(vis[x][y])continue;
			vis[x][y] = true;
			q.push(v);
		}
	}
}
int solve(){
	if(false == vis[D[1].first][D[1].second])return 0;
	for(int i = 0; i < n; i++)
	for(int j = 0; j < m; j++)
	if(false == vis[i][j])return 1;
	int siz = 0;
	for(int i = 0; i < n; i++)for(int j = 0; j < m; j++)siz += G[has(i,j)].size();
	if((siz>>1)==n*m-1)return 3;
	return 2;
}
int main() {
	while (~scanf("%d %d", &n, &m), n+m) {
		D.clear();
		for(int i = 0; i < n; i++){
			scanf("%s", s);
			for(int j = 0; j < m; j++)
			{
				G[has(i,j)].clear();
				if('0' <= s[j] && s[j]<='9')mp[i][j] = s[j]-'0';
				else mp[i][j] = s[j]-'A'+10;
			}
		}
		for(int i = 0; i < n; i++)
			for(int j = 0; j < m; j++)
				for(int k = 0; k < 4; k++)
				{
					int x = i+step[k][0], y = j+step[k][1];
					if(!inmap(x,y)){
					if((mp[i][j]&(1<<k))==0)
						D.push_back(pii(i,j));
						continue;
					}
					if((mp[i][j]&(1<<k))==0)
						add(i,j, x,y);
				}
		sort(D.begin(), D.end());
		D.erase(unique(D.begin(), D.end()), D.end());
		if((int)D.size()==1) D.push_back(D[0]);
		bfs(D[0].first, D[0].second);
		int ans = solve();
		if(ans == 0)puts("NO SOLUTION");
		else if(ans == 1) puts("UNREACHABLE CELL");
		else if(ans == 2)puts("MULTIPLE PATHS");
		else puts("MAZE OK");
	}
	return 0;
}
/*
1 8
2AAAAAAE

*/
G: 点击打开链接
CSU 1567 Reverse Rot

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int MAX_N = 57;
const char table[30] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_.";
int n;
char str[MAX_N];
int ID(char ch) {
	for (int i = 0; table[i]; ++i) if (table[i] == ch) return i;
}
int main() {
   while (1 == scanf("%d", &n)) {
		if (0 == n) break;
		scanf("%s", str);
		for (int i = 0; str[i]; ++i) {
			str[i] = table[(ID(str[i]) + n) % 28];
		}
		int len = strlen(str);
		for (int i = len - 1; i >= 0; --i) {
			putchar(str[i]);
		}
		puts("");
   }
    return 0;
}
H: 点击打开链接

CSU 1568 Shrine Maintenance

题意:输入M N, D 后面D个数

把一个半径为1000的圆N等分,再利用圆上N个点中的所有有效点画出恰好M个类三角形(我想说的是一个类三角形和圆心相连的边恰好有两条哟,即使第二图中只有一个点相连)

有效点:我们给圆中的点编号(1~N) ,那么是D个数中任意一个数的倍数 就是有效点。

问:

使得画出的M个类三角形中 最大的周长最小。 输出那个周长, 保留一位小数。

思路:

二分答案判可行。

我们把相邻的有效点两两相连

W的作用相当于是 断开了W条有效边

假设W=0,那么应该是所有边长相连,所以是一个环。

开始的做法是枚举环的第一个断点,但这样会t

而我们发现前面的因子间隔比较大,达到lcm后间隔就相同,这样断开任意一边都是等效的。也就是说枚举前面的因子即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>

using namespace std;

const int MAX_N = 8607;

int W, N, D;
int cnt;
bool vis[MAX_N];
int id[MAX_N];

void Clear() {
	cnt = 0;
	memset(vis, false, sizeof vis);
}

double get(int i, int j) {
	return 2000. * sin(acos(-1.) * abs(id[j] - id[i]) / N);
}

bool check(double ans, int j) {
	int w = W;
	double sum = 0;
	for (int i = (j+2)%cnt; ; i = (i+1)%cnt) {
		double now = get((i - 1+cnt)%cnt, i);
		if (sum + now <= ans) {
			sum += now;
		}
		else {
			sum = 0;
			--w;
			if (w < 0) return false;
		}
		if(i==j)break;
	}
	return true;
}

int main() {
	while (1 == scanf("%d", &W)) {
		if (0 == W) break;
		Clear();
		scanf("%d%d", &N, &D);
		for (int i = 0; i < D; ++i) {
			int v;
			scanf("%d", &v);
			for (int j = v; j <= N; j += v)
				vis[j] = true;
		}

		for (int i = 1; i <= N; ++i) if (vis[i])
			id[cnt++] = i;
		if(cnt <= W) {
			puts("2000.0");
			continue;
		}
		if(W == 0){
			puts("0.0"); continue;
		}
		W--;
		double ans = 1e8;
		for(int j = 0; j < min(100,cnt); j++){
			double l = 0, r = ans;
			for (int i = 0; i <30; ++i) {
				double mid = (l + r) / 2;
				if (check(mid, j)) r = mid;
				else l = mid;
			}
			ans = min(ans, r);
		}
		printf("%.1f\n", ans + 2000);
	}
    return 0;
}

I: 点击打开链接

CSU 1569 Wet Tiles

给定n*m的矩阵 时刻t  L个起点 W个墙

下面给出L个点的坐标

下面每4个数字给出每个墙的起点终点(墙要么平行于轴,要么45°倾斜)

问每个点bfs出去t下后,整个图被遍历了多少点。

简单bfs

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef pair<int, int> pii;
const int N = 1005;
char mp[N][N];
int vis[N][N];
int n, m, T;
queue<pii> que;
const int dx[] = {0, 0, -1, 1};
const int dy[] = {-1, 1, 0, 0};
int bfs() {
	int ans = 0;
	while(que.size() > 0) {
		pii tmp = que.front(); que.pop();
		int x = tmp.first, y = tmp.second;
		ans ++;
		if(vis[x][y] == T) continue;
		for(int i = 0; i < 4; i ++) {
			int nx = x + dx[i];
			int ny = y + dy[i];
			if(nx >= 0 && nx < n && ny >= 0 && ny < m && vis[nx][ny] == 0) {
				vis[nx][ny] = vis[x][y] + 1;
				que.push(make_pair(nx, ny));
			}
		}
	}
	return ans;
}
int main() {
	while(~scanf("%d", &m)) {
		if(m == -1) break;
		memset(vis, 0, sizeof vis);
		int L, W;
		scanf("%d%d%d%d", &n, &T, &L, &W);
		for(int i = 0, x, y; i < L; i ++) {
			scanf("%d%d", &x, &y);
			swap(x, y);
  			y--, x = n - x;
			que.push(make_pair(x, y));
			vis[x][y] = 1;
		}
		for(int i = 0, x1, x2, y1, y2; i < W; i ++) {
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			swap(x1, y1); swap(x2, y2);
  			y1--, y2--;
			x1 = n - x1;
			x2 = n - x2;
			if(x1 == x2) {
				if(y1 < y2) {
					while(y1 <= y2) {
						vis[x1][y1++] = -1;
					}
				} else {
					while(y1 >= y2) {
						vis[x1][y1--] = -1;
					}
				}
			} else if(y1 == y2) {
				if(x1 < x2) {
					while(x1 <= x2) {
						vis[x1++][y1] = -1;
					}
				} else {
					while(x1 >= x2) {
						vis[x1--][y1] = -1;
					}
				}
			} else {
				if(x1 < x2) {
					if(y1 < y2) {
						while(x1 <= x2) {
							vis[x1++][y1++] = -1;
						}
					} else {
						while(x1 <= x2) {
							vis[x1++][y1--] = -1;
						}
					}
				} else {
					if(y1 < y2) {
						while(x1 >= x2) {
							vis[x1--][y1++] = -1;
						}
					} else {
						while(x1 >= x2) {
							vis[x1--][y1--] = -1;
						}
					}
				}
			}
		}
		printf("%d\n", bfs());	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值