[2021.8纪中集训Day14]

@

[2021.8纪中集训Day14]

1312. 老曹的忧郁

题目

Description

  我们的主角——老曹,现在十分忧郁。原因是他在玩一个困难的游戏。
 游戏规则如下:
 有(N+1)*n/2个圆盘,在平面上摆成了一个变长为N个圆盘的等边三角形。每个圆盘上标有一个小写字母(‘a’_’z’),如下图所示。
 对于每个字母,当我们可以由标为这个字母的圆盘为顶点,构成等边三角形时,我们称这个字母为不和谐的。例如途中的a和c。
  现在给你N和这个等边三角形上的字母,要求哪些字母是不和谐的。

Input

  第一行:一个整数,N(1<=N<=12)
 第二行:(N+1)*N/2个小写字母

Output

  一行:按字典序输出所有不和谐的字母,如果没有不和谐的字母,则输出“Harmonious”。

Sample Input

样例输入1:
3
aaaaaa

样例输入2:
3
abcdef

Sample Output

样例输出1:
a

样例输出2:
Harmonious

注意,如果输出多个字母,中间没有空格,比如那张图对应的答案就是ac,题目差评😠

思路

一道水题,建个系,搜索一下,判下等边三角形就好了:

纵坐标\横坐标 -3 -2 1 0 1 2 3
0 a
\(-\sqrt3\) b c
\(-2\sqrt 3\) c d d
\(-3\sqrt 3\) a d c a

比较难看

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;

const double eps = 1e-7;
const double sqrt3 = 1.73205081;

struct POINT {
	double x , y;
};
POINT make(double x , double y) {
	POINT tmp;
	tmp.x = x , tmp.y = y;
	return tmp;
}
double GetDist(POINT a , POINT b) {
	return sqrt(
	           (a.x - b.x) * (a.x - b.x) +
	           (a.y - b.y) * (a.y - b.y)
	       );
}
inline bool fequal(double a , double b) {
	return fabs(a - b) < eps;
}
bool CheckTriangle(POINT a , POINT b  , POINT c) {
	return fequal(GetDist(a , b) , GetDist(a , c)) && fequal(GetDist(a , c) , GetDist(b , c));
}

int n;
vector <POINT> a[30];

bool result;
POINT rec[5];
void dfs(int id , int pos , int rest) {
	if(result)
		return;
	if(rest == 0) {
		if(CheckTriangle(rec[1] , rec[2] , rec[3]))
			result = true;
		return;
	}
	if(pos == a[id].size())
		return ;
	dfs(id , pos + 1 , rest);
	rec[rest] = a[id][pos];
	dfs(id , pos + 1 , rest - 1);
}
int main() {
	cin >> n;
	for(int i = 0 , cnt = 0 ; i < n ; i++) {
		for(int j = -i ; j <= i ; j += 2) {
			char c;
			cin >> c;
			a[c - 'a'].push_back(make(sqrt3 * (double)cnt , j));
		}
		--cnt;
	}
	
	bool flag = false;
	for(int i = 0 ; i < 26 ; i++) {
		result = false;
		dfs(i , 0 , 3);
		flag |= result;
		if(result)
			putchar(i + 'a');
	}
	if(!flag)
		puts("Harmonious");
	return 0;
}
/*
4
abccddadca
*/

1313. 老曹骑士

题目

Description

  我们的主角——老曹陨落于国际象棋棋盘,成为了一位老曹骑士,于是,他开始走“日”字型路线。
 在一张N*N的棋盘上,有K只邪恶的河蟹,骑士曹现在要消灭这些河蟹。
 要求曹从任意一只河蟹出发,通过他“日”字型的跳跃,到达这K个点至少一次,并最终回到起点。
 现在已知棋盘的大小N,和这K只河蟹的位置(棋盘的左上角坐标记为(1,1),右下角坐标记为(N,N)。
 询问:曹最少要跳多少步。

Input

  第一行:两个整数,N,K(4<=N<=20,1<=K<=10)
 接下来K行:每行两个整数X,Y,表示河蟹所在位置。

Output

  一个整数,表示曹所需要条的最少步数。

Sample Input

8 3
2 3
4 5
6 7

Sample Output

12

思路

状压DP裸题,设\(f_{i,j}\)表示当前消灭的河蟹的集合为\(i\)(状压),最后消灭的一只河蟹编号为\(j\),外面在套一个循环枚举起点即可.

关于两点距离的预处理,跑一遍Floyd即可.

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

int read() {
	int re = 0;
	char c = getchar();
	bool negt = false;
	while(c < '0' || c > '9')
		negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return negt ? -re : re;
}

const int deltaxy[8][2] = {
	1,2 , 1,-2 , 2,1 , 2,-1 , -1,2 , -1,-2 , -2,1 , -2,-1
};
const int N = 25 , M = 25;

int n , m;
int x[M] , y[M];

int id[N][N] , cnt;
int map[N * N][N * N];
#define dis(x0 , y0 , x1 , y1) map[id[x0][y0]][id[x1][y1]]

int f[1 << 12][12];
bool vis[1 << 12][12];

struct State {
	int set , laspos ;
};
State make(int set , int laspos) {
	State tmp;
	tmp.set = set , tmp.laspos = laspos;
	return tmp;
}
std::queue <State> q;

int min(int a, int b) {
	return a < b ? a : b;
}
int main() {
	n = read() , m = read();
	for(int i = 0 ; i < n ; i++)
		for(int j = 0 ; j < n ; j++)
			id[i][j] = cnt++;

	for(int i = 0 ; i < m ; i++)
		x[i] = read() - 1 , y[i] = read() - 1;

	memset(map , 0x3f , sizeof(map));

	for(int i = 0 ; i < n ; i++)
		for(int j = 0 ; j < n ; j++) {
			for(int k = 0 ; k < 8 ; k++) {
				int gx = i + deltaxy[k][0] , gy = j + deltaxy[k][1];
				if(gx >= 0 && gy >= 0 && gx < n && gy < n)
					dis(i , j , gx , gy) = 1;
			}
		}

	for(int k = 0 ; k < cnt ; k++)//Floyd
		for(int i = 0 ; i < cnt ; i++)
			for(int j = 0 ; j < cnt ; j++)
				if(map[i][j] > map[i][k] + map[k][j])
					map[i][j] = map[i][k] + map[k][j];

	if(m == 1) {
		std::cout << 0;
		return 0;
	}
	int ans = 0x3fffffff;
	for(int begin = 0 ; begin < m ; begin++) {
		memset(f, 0x3f , sizeof(f));
		f[1 << begin][begin] = 0 , q.push(make(1 << begin , begin)) , vis[1 << begin][begin] = true;

		while(!q.empty()) {
			State k = q.front();
			q.pop();
			for(int i = 0 ; i < m ; i++)
				if((k.set & (1 << i)) == 0) {
					int newset = (k.set | (1 << i));
					if(!vis[newset][i])
						q.push(make(newset , i)) , vis[newset][i] = true;
					f[newset][i] = min(
					                   f[newset][i] ,
					                   f[k.set][k.laspos] + dis(x[k.laspos] , y[k.laspos] , x[i] , y[i])
					               );
				}
		}
		for(int i = 0 ; i < m ; i++)
			ans = min(ans , f[(1 << m) - 1][i] + dis(x[begin] , y[begin] , x[i] , y[i]));
	}

	std::cout << ans;
	return 0;
}

1314. 稳定的数字

题目

Description

  定义一种操作,经过该操作,可以得到一个数中所有数字的乘积(原数至少要是个两位数)。比如679经过一次操作可以得到378。  你的任务读入一个数,计算经过一次操作得到它的最小的数是多少。

Input

  仅一行,表示一个十进制数。数的长度可能到达1000位。

Output

  经过一次操作可以得到这个数的最小的数。如果没有这样的数,输出“There is no such number.”(不包括引号)

Sample Input

输入1:
0
输入2:
18
输入3:
51

Sample Output

输出1:
10
输出2:
29
输出3:
There is no such number.

思路

又是一道水题.

因为最后的数字最小,就要位数最小,把输入的数分解\(1\sim 9\)的因数即可(注意,像数字18,我们分解为\(9\times2\)而不是\(3\times3\times2\),以减少位数).

网上抠了个高精模板.

代码

#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>

//ABOUT "BigIntTiny":
// filename:    bigint_tiny.h
// author:      baobaobear
// create date: 2021-02-10
// This library is compatible with C++03
// https://github.com/Baobaobear/MiniBigInteger
struct BigIntTiny {
	int sign;
	std::vector<int> v;

	BigIntTiny() : sign(1) {}
	BigIntTiny(const std::string &s) {
		*this = s;
	}
	BigIntTiny(int v) {
		char buf[21];
		sprintf(buf, "%d", v);
		*this = buf;
	}
	void zip(int unzip) {
		if (unzip == 0) {
			for (int i = 0; i < (int)v.size(); i++)
				v[i] = get_pos(i * 4) + get_pos(i * 4 + 1) * 10 + get_pos(i * 4 + 2) * 100 + get_pos(i * 4 + 3) * 1000;
		} else
			for (int i = (v.resize(v.size() * 4), (int)v.size() - 1), a; i >= 0; i--)
				a = (i % 4 >= 2) ? v[i / 4] / 100 : v[i / 4] % 100, v[i] = (i & 1) ? a / 10 : a % 10;
		setsign(1, 1);
	}
	int get_pos(unsigned pos) const {
		return pos >= v.size() ? 0 : v[pos];
	}
	BigIntTiny &setsign(int newsign, int rev) {
		for (int i = (int)v.size() - 1; i > 0 && v[i] == 0; i--)
			v.erase(v.begin() + i);
		sign = (v.size() == 0 || (v.size() == 1 && v[0] == 0)) ? 1 : (rev ? newsign * sign : newsign);
		return *this;
	}
	std::string to_str() const {
		BigIntTiny b = *this;
		std::string s;
		for (int i = (b.zip(1), 0); i < (int)b.v.size(); ++i)
			s += char(*(b.v.rbegin() + i) + '0');
		return (sign < 0 ? "-" : "") + (s.empty() ? std::string("0") : s);
	}
	bool absless(const BigIntTiny &b) const {
		if (v.size() != b.v.size()) return v.size() < b.v.size();
		for (int i = (int)v.size() - 1; i >= 0; i--)
			if (v[i] != b.v[i]) return v[i] < b.v[i];
		return false;
	}
	BigIntTiny operator-() const {
		BigIntTiny c = *this;
		c.sign = (v.size() > 1 || v[0]) ? -c.sign : 1;
		return c;
	}
	BigIntTiny &operator=(const std::string &s) {
		if (s[0] == '-')
			*this = s.substr(1);
		else {
			for (int i = (v.clear(), 0); i < (int)s.size(); ++i)
				v.push_back(*(s.rbegin() + i) - '0');
			zip(0);
		}
		return setsign(s[0] == '-' ? -1 : 1, sign = 1);
	}
	bool operator<(const BigIntTiny &b) const {
		return sign != b.sign ? sign < b.sign : (sign == 1 ? absless(b) : b.absless(*this));
	}
	bool operator==(const BigIntTiny &b) const {
		return v == b.v && sign == b.sign;
	}
	BigIntTiny &operator+=(const BigIntTiny &b) {
		if (sign != b.sign) return *this = (*this) - -b;
		v.resize(std::max(v.size(), b.v.size()) + 1);
		for (int i = 0, carry = 0; i < (int)b.v.size() || carry; i++) {
			carry += v[i] + b.get_pos(i);
			v[i] = carry % 10000, carry /= 10000;
		}
		return setsign(sign, 0);
	}
	BigIntTiny operator+(const BigIntTiny &b) const {
		BigIntTiny c = *this;
		return c += b;
	}
	void add_mul(const BigIntTiny &b, int mul) {
		v.resize(std::max(v.size(), b.v.size()) + 2);
		for (int i = 0, carry = 0; i < (int)b.v.size() || carry; i++) {
			carry += v[i] + b.get_pos(i) * mul;
			v[i] = carry % 10000, carry /= 10000;
		}
	}
	BigIntTiny operator-(const BigIntTiny &b) const {
		if (sign != b.sign) return (*this) + -b;
		if (absless(b)) return -(b - *this);
		BigIntTiny c;
		for (int i = 0, borrow = 0; i < (int)v.size(); i++) {
			borrow += v[i] - b.get_pos(i);
			c.v.push_back(borrow);
			c.v.back() -= 10000 * (borrow >>= 31);
		}
		return c.setsign(sign, 0);
	}
	BigIntTiny operator*(const BigIntTiny &b) const {
		if (b < *this) return b **this;
		BigIntTiny c, d = b;
		for (int i = 0; i < (int)v.size(); i++, d.v.insert(d.v.begin(), 0))
			c.add_mul(d, v[i]);
		return c.setsign(sign * b.sign, 0);
	}
	BigIntTiny operator/(const BigIntTiny &b) const {
		BigIntTiny c, d;
		d.v.resize(v.size());
		double db = 1.0 / (b.v.back() + (b.get_pos((unsigned)b.v.size() - 2) / 1e4) +
		                   (b.get_pos((unsigned)b.v.size() - 3) + 1) / 1e8);
		for (int i = (int)v.size() - 1; i >= 0; i--) {
			c.v.insert(c.v.begin(), v[i]);
			int m = (int)((c.get_pos((int)b.v.size()) * 10000 + c.get_pos((int)b.v.size() - 1)) * db);
			c = c - b * m, d.v[i] += m;
			while (!(c < b))
				c = c - b, d.v[i] += 1;
		}
		return d.setsign(sign * b.sign, 0);
	}
	BigIntTiny operator%(const BigIntTiny &b) const {
		return *this - *this / b * b;
	}
	bool operator>(const BigIntTiny &b) const {
		return b < *this;
	}
	bool operator<=(const BigIntTiny &b) const {
		return !(b < *this);
	}
	bool operator>=(const BigIntTiny &b) const {
		return !(*this < b);
	}
	bool operator!=(const BigIntTiny &b) const {
		return !(*this == b);
	}
};

using namespace std;
BigIntTiny a;

char s[1010];
int c[1010];

int main() {
	scanf("%s" , s);

	if(strlen(s) == 1) {
		putchar('1') , putchar(s[0]);
		return 0;
	}

	a = s;

	for(int i = 9 ; i >= 2 ; i--) {
		while(a % i == 0)
			a = a / i , ++c[i];
	}
	
	
	if(a > 1)
		puts("There is no such number.");
	else {
		for(int i = 2 ; i <= 9 ; i++) {
			for(int j = 1 ; j <= c[i] ; j++)
				putchar(i + '0');
		}
	}
	return 0;
}

封锁阳光大学

题目

题目描述

曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。

阳光大学的校园是一张由 \(n\) 个点构成的无向图,\(n\) 个点之间由 \(m\) 条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。

询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。

输入格式

第一行两个正整数,表示节点数和边数。
接下来 \(m\) 行,每行两个整数 \(u,v\),表示点 \(u\) 到点 \(v\) 之间有道路相连。

输出格式

仅一行如果河蟹无法封锁所有道路,则输出 Impossible,否则输出一个整数,表示最少需要多少只河蟹。

输入输出样例

输入 #1

3 3
1 2
1 3
2 3

输出 #1

Impossible

输入 #2

3 2
1 2
2 3

输出 #2

1

说明/提示

【数据规模】
对于 \(100\%\) 的数据,\(1\le n \le 10^4\)\(1\le m \le 10^5\),保证没有重边。

思路

题意简述:\(n\)个点,01染色,同一条边相连的两个点不能染一种颜色,每个点都要染色,问最少要染多少个颜色1.

其实可以发现,只要一个点的颜色确定,整个连通块的颜色都确定了.

枚举即可.

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int read() {
	int re = 0;
	char c = getchar();
	bool negt = false;
	while(c < '0' || c > '9')
		negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return negt ? -re : re;
}

const int N = 10010 , M = 100010;
struct EDGE {
	int to , nxt;
}ed[M * 2];
int head[N];
void addedge(int u , int v) {
	static int cnt;
	++cnt;
	ed[cnt].to = v , ed[cnt].nxt = head[u] , head[u] = cnt;
}

int n , m;
int color[N];
int dfs(int u) {
	int sum = 0;
	for(int i = head[u] ; i ; i = ed[i].nxt) {
		int v = ed[i].to;
		if(color[v] == -1) {
			color[v] = color[u] ^ 1;//染相反颜色
			int tmp = dfs(v);
			if(tmp == -1)
				return -1;
			else
				sum += tmp;
		} else {
			if(color[v] != color[u] ^ 1)
				return -1;
		}
	}
	return sum + color[u];
}
void clear(int u) {//清除染色
	color[u] = -1;
	for(int i = head[u] ; i ; i = ed[i].nxt) {
		if(color[ed[i].to] != -1)
			clear(ed[i].to);
	}
}

int main() {
	n = read() , m = read();
	for(int i = 1 ; i <= m ; i++) {
		int u = read() , v = read();
		addedge(u , v);
		addedge(v , u);
	}
	
	memset(color , -1 , sizeof(color));//-1表示未染色
	int ans = 0;
	for(int i = 1 ; i <= n ; i++)
		if(color[i] == -1) {//这里写得比较丑,其实就是枚举第i个点的颜色,取更优的方案,其实也可以不用这么写,直接连通块点数一减好像就行
			int tmp , tmp1;
			color[i] = 0;
			tmp = dfs(i);
			tmp = tmp == -1 ? 0x3fffffff : tmp;
			
			clear(i);
			
			color[i] = 1;
			tmp1 = dfs(i);
			tmp1 = tmp1 == -1 ? 0x3fffffff : tmp1;
			if(tmp == 0x3fffffff && tmp1 == 0x3fffffff) {
				ans = -1;
				break;
			}
			ans += min(tmp , tmp1);
		}
	
	if(ans == -1)
		puts("Impossible");
	else
		cout << ans;
	return 0;
}
posted @ 2021-08-25 16:18  追梦人1024  阅读(60)  评论(0编辑  收藏  举报