VJudge9.22

VJudge2019.9.22

A CodeForces1117C
如果之前不知道风向就不方便作决定,二分刚好就能写。
一道我都能想出来的题

#include
#include
#include
#include
using namespace std;
#define ll long long
int main()
{
	//freopen("in.txt", "r", stdin);
	ll x1, y1, x2, y2;
	cin >> x1 >> y1 >> x2 >> y2;
	int n;
	scanf("%d", &n);
	string wind;
	cin >> wind;
	ll u = 0, r = 0,d = 0, l = 0;
	for (int i = 0; i < n; i++) {
		if (wind[i] == 'U')u++;
		else if (wind[i] == 'R')r++;
		else if (wind[i] == 'L')l++;
		else d++;
	}
	ll left = 1; ll right = 2e14;
	ll ans = -1;	
	while (left <= right) {
		ll mid = (left + right) >> 1;
		ll c = mid / n;
		ll k = mid % n;
		ll endx, endy;
		endx = x1 + (r - l)*c;
		for (int i = 0; i < k; i++) {
			if (wind[i] == 'R')endx++;
			else if (wind[i] == 'L')endx--;
		}
		endy = y1 + (u - d)*c;
		for (int i = 0; i < k; i++) {
			if (wind[i] == 'U')endy++;
			else if (wind[i] == 'D')endy--;
		}
		ll judge = abs(endx - x2) + abs(endy - y2);
		if (judge <= mid) {
			right = mid - 1;
			ans = mid;
		}
		else left = mid + 1;
	}
	cout << ans;
}

B codeforces 920E
给出补图,求联通分量个数和大小
以为是并查集+补图求完全K分图,but不是
老老实实的存边搜索,用set存查找删除会更高效。
要从set里面删元素的话先存在一个temp里面再删就好了,直观一些

#include
#include
#include
#include
#include
using namespace std;
set<int> node[200005];
set<int> total;
int tempans = 0;
void dfs(int x) {
	tempans++;
	set<int>::iterator it;
	set<int> temp;
	for (it = total.begin(); it != total.end();it++) {
		if (node[x].find(*it) == node[x].end()) {
			temp.insert(*it);
		}
	}
	for (it = temp.begin(); it != temp.end(); it++)total.erase(*it);
	for (it = temp.begin(); it != temp.end(); it++)dfs(*it);
}
int main()
{
	//freopen("in.txt", "r", stdin);
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		total.insert(i);
	}
	while (m--) {
		int u, v;
		scanf("%d%d", &u, &v);
		node[u].insert(v);
		node[v].insert(u);
	}
	vector<int> vec;
	for (int i = 1; i <= n; i++) {
		if (total.find(i) == total.end())continue;
		total.erase(i);
		tempans = 0;
		dfs(i);
		vec.push_back(tempans);
	}
	sort(vec.begin(), vec.end());
	printf("%d\n", vec.size());
	for (int i = 0; i < vec.size(); i++) {
		printf("%d ", vec[i]);
	}
}

C codeforces 920F
应该是很经典的一道线段树?
单点修改,区间求和。优化是维护一个区间的最值,如果是2,那么求的因子也是2,就不用继续往下修改。
先打表求出因子的个数。

#include
#include
#include
#include
using namespace std;
#define ll long long
const int maxn = 3e5+5;
int add[maxn << 2];
ll sum[maxn << 2];
ll maxx[maxn << 2];
int num[1000005];
void init() {//非常耿直的打表
	for (int i = 1; i < 1000005; i++) {
		for (int j = i; j < 1000005; j += i)num[j]++;
	}
}
void pushup(int rt)
{
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
	maxx[rt] = max(maxx[rt << 1], maxx[rt << 1 | 1]);
}
void build(int l, int r, int rt)
{
	if (l == r)
	{
		scanf("%lld", &sum[rt]);
		maxx[rt] = sum[rt];
		return;
	}
	int m = (l + r) >> 1;
	build(l, m, rt << 1);
	build(m + 1, r, rt << 1 | 1);
	pushup(rt);
}
void update(int L, int R, int l, int r, int rt)
{
	if (maxx[rt] <= 2)return;
	if (l==r)
	{
		sum[rt] = num[sum[rt]];
		maxx[rt] = sum[rt];
		return;
	}
	//pushdown(rt, r - l + 1);
	int m = (l + r) >> 1;
	if (L <= m)update(L, R, l, m, rt << 1);
	if (m < R) update(L, R, m + 1, r, rt << 1 | 1);
	pushup(rt);
}
ll query(int L, int R, int l, int r, int rt)
{
	if (L <= l && r <= R)
		return sum[rt];
	int m = (l + r) >> 1;
	ll ret = 0;
	if (L <= m) ret += query(L, R, l, m, rt << 1);
	if (m < R)  ret += query(L, R, m + 1, r, rt << 1 | 1);
	return ret;
}
int main()
{
	//freopen("in.txt", "r", stdin);
	init();
	int n, m;
	scanf("%d%d", &n, &m);
	build(1, n, 1);
	while (m--) {
		int op;
		scanf("%d", &op);
		if (op == 1) {//replace
			int l, r;
			scanf("%d%d", &l, &r);
			update(l, r, 1, n, 1);
		}
		else {//sum
			int l, r;
			scanf("%d%d", &l, &r);
			printf("%lld\n", query(l, r, 1, n, 1));
		}
	}
}

D codeforces919D
想到是dp了,但是写的太复杂了。应该是先到终点然后再回溯dp的(也许都是这种套路?)dfs:判环用in数组,剪枝用vis数组,从终点开始更新之前的点。因为是从后往前更新的所以不需要特意求出起点。没剪枝所以就T了Q-Q
这种方法貌似也容易超时??还有一种是用拓扑排序。
无向图用并查集判环,有向图用拓扑排序判环
其实就是一个BFS,然后用in保存入度数,访问到一次入度就减一,不是0就说明还有到它的点,就再加到queue中。是从起点开始一步步更新之后的点。
?我就是想不到Q-Q太菜了

#include
#include
#include
#include
#include
using namespace std;
const int maxn = 3e5 + 5;
int in[maxn];
vector<int> g[maxn];
int n, m;
char s[maxn];
queue<int> que;
int dp[maxn][26];
void bfs() {
	for (int i = 1; i <= n; i++) {
		if (!in[i]) {
			que.push(i);
			dp[i][s[i] - 'a']++;
		}
	}
	int cnt = 0;
	while (que.size()) {
		int u = que.front();
		que.pop();
		cnt++;
		for (int i = 0; i < g[u].size(); i++) {
			int v = g[u][i];
			in[v]--;
			if (in[v]) {
				for (int i = 0; i < 26; i++) {
					if (s[v] == i + 'a')
						dp[v][i] = max(dp[v][i], dp[u][i] + 1);
					else
						dp[v][i] = max(dp[u][i], dp[v][i]);
				}
			}
			else {
				que.push(v);
				for (int i = 0; i < 26; i++) {
					if (s[v] == i + 'a')
						dp[v][i] = max(dp[v][i], dp[u][i] + 1);
					else
						dp[v][i] = max(dp[u][i], dp[v][i]);
				}
			}

		}
	}
	if (cnt == n) {
		int ans = 0;
		for (int i = 1; i <= n; i++) {
			for (int j = 0; j < 26; j++) {
				ans = max(ans, dp[i][j]);
			}
		}
		printf("%d", ans);
	}
	else {
		printf("-1\n");
	}
}
int main()
{
	//freopen("in.txt", "r", stdin);
	memset(in, 0, sizeof(in));
	memset(dp, 0, sizeof(dp));
	scanf("%d%d", &n, &m);
	scanf("%s", s + 1);
	while (m--) {
		int u, v;
		scanf("%d%d", &u, &v);
		g[u].push_back(v);
		in[v]++;
	}
	bfs();
}

E codeforces917A
看了一下,觉得是dp,是我不会写的dp

看了题解,居然是思维题,然后果然是贪心思维题。(其实贪心就是思维吧??)是我不会写的贪心。
是我太菜了

F codeforces917B
不会写…看了题解才知道是dp+博弈,必胜点和必败点
dp[i][j][v]表示先手在i点,后手在j点,上一轮权值为v的胜负情况。
才接触到博弈题=-=是我太菜了

#include
#include
#include
#include
using namespace std;
const int maxn = 105;
const int maxm = 1e5 + 5;
struct edge {
	int v, w;
	int next;
}e[maxm];
int total = 0;
int head[maxn];
void addedge(int u, int v, int w) {
	total++;
	e[total].v = v;
	e[total].w = w;
	e[total].next = head[u];
	head[u] = total;
}
int dp[maxn][maxn][30];
//1是必胜 2是必败
int dfs(int i, int j, int prew) {
	if (dp[i][j][prew])return dp[i][j][prew];
	for (int k = head[i]; k; k = e[k].next) {
		int v = e[k].v;
		int w = e[k].w;
		if (w >= prew) {
			if (dfs(j, v, w) == 2) {//如果下一步是必败的情况
				return dp[i][j][w] = 1;//这一步一定是必胜的
			}
		}
	}
	return dp[i][j][prew] = 2;
}
int main()
{
	freopen("in.txt", "r", stdin);
	memset(dp, 0, sizeof(dp));
	int n, m;
	scanf("%d%d", &n, &m);
	while (m--) {
		int u, v;
		char value;
		scanf("%d %d %c", &u, &v, &value);
		addedge(u, v, value - 'a');
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (dfs(i, j, 0) == 1)printf("A");
			else printf("B");
		}
		printf("\n");
	}
}

你可能感兴趣的:(日常练习补题)