首页 > 其他分享 >2023冲刺清北营8

2023冲刺清北营8

时间:2023-04-28 22:25:15浏览次数:40  
标签:cnt val int ans long 清北营 冲刺 2023 now

T1 内鬼

由于两名内鬼的行动互不干扰,因此可以单独求解后暴力合并。

很容易想到一种 dp 做法,设 \(f_{i,S}\) 表示当前位于第 \(i\) 个点,当前刀掉的人组成的集合为 \(S\) 时的最短时间,转移时考虑通过一条边或留在此处继续刀人,很容易使用 Dijikstra 进行转移,然而……

它 TLE 了……考虑一个优化,从小到大枚举集合 \(S\) ,同层之间使用 Dijikstra 转移,异层之间不使用 Dijikstra ,常数会小很多。

code

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
const int max1 = 1e4, max2 = 8, max3 = 1 << 8;
const int inf = 0x3f3f3f3f;

int n, m, k;
struct Node
	{ int next, v, w; } edge[max1 * 4 + 5];
int head[max1 + 5], total;
void Add ( int u, int v, int w )
{
	edge[++total].v = v;
	edge[total].w = w;
	edge[total].next = head[u];
	head[u] = total;
	return;
}

int len, Tmax;
struct Option
{
	int id, u, tim;
	bool operator < ( const Option &A ) const
		{ return tim < A.tim; }
}opt[max1 * 10 + 5];
vector <int> tim[max1 + 5][max2 + 5];

int f[max1 + 5][max3 + 5];
bool vis[max1 + 5];
struct Point
{
	int u, s, val;
	Point () {}
	Point ( int __u, int __val )
		{ u = __u, val = __val; }
	bool operator < ( const Point &A ) const
		{ return val > A.val; }
};
priority_queue <Point> que;

int g[max3 + 5], h[max3 + 5];

void Solve ( int u )
{
	for ( int i = 1; i <= n; i ++ )
		for ( int s = 0; s < 1 << k; s ++ )
			f[i][s] = inf;
	f[u][0] = 0;
	for ( int s = 0; s < 1 << k; s ++ )
	{
		while ( !que.empty() )
			que.pop();
		for ( int i = 1; i <= n; i ++ )
			que.push(Point(i, f[i][s])), vis[i] = false;
		while ( !que.empty() )
		{
			int now = que.top().u;
			que.pop();
			if ( vis[now] )
				continue;
			if ( f[now][s] > Tmax )
				break;
			vis[now] = true;
			for ( int i = head[now]; i; i = edge[i].next )
			{
				int v = edge[i].v, w = edge[i].w;
				if ( !vis[v] && f[v][s] > f[now][s] + w )
				{
					f[v][s] = f[now][s] + w;
					que.push(Point(v, f[v][s]));
				}
			}
			for ( int i = 1; i <= k; i ++ )
			{
				if ( !( s >> i - 1 & 1 ) )
				{
					int pos = *lower_bound(tim[now][i].begin(), tim[now][i].end(), f[now][s]);
					f[now][s | 1 << i - 1] = min(f[now][s | 1 << i - 1], pos);
				}
			}
		}
	}
	return;
}

int main ()
{
	freopen("ghost.in", "r", stdin);
	freopen("ghost.out", "w", stdout);
	
	scanf("%d%d%d", &n, &m, &k);
	for ( int i = 1, u, v, w; i <= m; i ++ )
	{
		scanf("%d%d%d", &u, &v, &w);
		Add(u, v, w), Add(v, u, w);
	}
	
	scanf("%d%d", &len, &Tmax);
	for ( int i = 1; i <= len; i ++ )
		scanf("%d%d%d", &opt[i].id, &opt[i].u, &opt[i].tim);
	sort(opt + 1, opt + 1 + len);
	for ( int i = 1; i <= len; i ++ )
		tim[opt[i].u][opt[i].id].push_back(opt[i].tim);
	for ( int i = 1; i <= n; i ++ )
		for ( int j = 1; j <= k; j ++ )
			tim[i][j].push_back(inf);
	int u, v;
	scanf("%d%d", &u, &v);

	Solve(u);
	for ( int s = 0; s < 1 << k; s ++ )
	{
		g[s] = inf;
		for ( int i = 1; i <= n; i ++ )
			g[s] = min(g[s], f[i][s]);
	}

	Solve(v);
	for ( int s = 0; s < 1 << k; s ++ )
	{
		h[s] = inf;
		for ( int i = 1; i <= n; i ++ )
			h[s] = min(h[s], f[i][s]);
	}

	int ans = inf;
	for ( int s = 0; s < 1 << k; s ++ )
		for ( int t = 0; t < 1 << k; t ++ )
			if ( !( s & t ) && ( s | t ) == ( 1 << k ) - 1 && g[s] != inf && h[t] != inf )
				ans = min(ans, max(g[s], h[t]));
	if ( ans > Tmax )
		ans = -1;
	printf("%d\n", ans);
	return 0;
}

T2 树上最长上升子序列

由于处理树链信息,因此考虑点分治。

如果我们可以得到跨过分治中心的以权值 \(x\) 结尾的最长下降子序列的长度,显然当前节点跨过分治中心的答案可以直接查询,因此考虑 dp 求解这段长度,很容易想到用动态开点线段树维护,使用线段树合并维护所有经过分治中心的链的信息,可以做到 \(O(n\log^2n)\) 。(然而我的常数大极了)

code

#include <cstdio>
#include <algorithm>
#include <vector>
#include <ctime>
#include <iostream>
#include <climits>
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
using namespace std;
const int max1 = 2e5;
const int inf = 0x3f3f3f3f;

int n, a[max1 + 5], save[max1 + 5], len;
vector <int> edge[max1 + 5];
int siz[max1 + 5], root, point[max1 + 5], cnt;
bool vis[max1 + 5];
int ans[max1 + 5];

int cnt_merge, cnt_insert, cnt_change, cnt_query;

struct Segment_Tree
{
	#define lson(now) tree[now].son[0]
	#define rson(now) tree[now].son[1]

	struct Data
		{ int son[2], max_val; } tree[max1 * 100 + 5];
	int root[max1 + 5], total;

	void Clear ()
		{ total = lson(0) = rson(0) = tree[0].max_val = 0; return; }

	void Push_Up ( int now )
	{
		tree[now].max_val = max(tree[lson(now)].max_val, tree[rson(now)].max_val);
		return;
	}

	void Insert ( int &now, int L, int R, int pos, int val )
	{
		++cnt_insert;
		if ( !now )
			{ now = ++total; lson(now) = rson(now) = tree[now].max_val = 0; }

		if ( L == R )
			{ tree[now].max_val = max(tree[now].max_val, val); return; }
		
		int mid = L + R >> 1;
		if ( pos <= mid )
			Insert(lson(now), L, mid, pos, val);
		else
			Insert(rson(now), mid + 1, R, pos, val);
		Push_Up(now);
		return;
	}

	void Insert ( int now, int pos, int val )
		{ return Insert(root[now], 1, len, pos, val); }

	void Change ( int &now, int L, int R, int pos, int val )
	{
		++cnt_change;
		if ( !now )
			{ now = ++total; lson(now) = rson(now) = tree[now].max_val = 0; }

		if ( L == R )
			{ tree[now].max_val = val; return; }
		
		int mid = L + R >> 1;
		if ( pos <= mid )
			Change(lson(now), L, mid, pos, val);
		else
			Change(rson(now), mid + 1, R, pos, val);
		Push_Up(now);
		return;
	}

	void Change ( int now, int pos, int val )
		{ return Change(root[now], 1, len, pos, val); }

	int Merge ( int x, int y, int L, int R )
	{
		++cnt_merge;
		if ( !tree[x].max_val )
			return y;
		else if ( !tree[y].max_val )
			return x;
		
		if ( L == R )
			{ tree[x].max_val = max(tree[x].max_val, tree[y].max_val); return x; }

		int mid = L + R >> 1;
		lson(x) = Merge(lson(x), lson(y), L, mid);
		rson(x) = Merge(rson(x), rson(y), mid + 1, R);
		Push_Up(x);
		return x;
	}

	void Merge ( int x, int y )
		{ root[x] = Merge(root[x], root[y], 1, len); return; }
	
	int Query ( int now, int L, int R, int pos )
	{
		++cnt_query;
		if ( !tree[now].max_val )
			return 0;
		
		if ( L == R )
			return tree[now].max_val;
		int mid = L + R >> 1;
		if ( pos <= mid )
			return Query(lson(now), L, mid, pos);
		return Query(rson(now), mid + 1, R, pos);
	}

	int Query ( int now, int pos )
		{ return Query(root[now], 1, len, pos); }
	
	int Query_Suffix ( int now, int L, int R, int pos )
	{
		++cnt_query;
		if ( !tree[now].max_val )
			return 0;
		if ( L == R )
			return tree[now].max_val;
		int mid = L + R >> 1;
		if ( pos <= mid )
			return max(tree[rson(now)].max_val, Query_Suffix(lson(now), L, mid, pos));
		return Query_Suffix(rson(now), mid + 1, R, pos);
	}

	int Query_Suffix ( int now, int pos )
	{
		if ( pos == len + 1 )
			return 0;
		return Query_Suffix(root[now], 1, len, pos);
	}
}Tree;

void Get_Size ( int now, int fa )
{
	siz[now] = 1;
	for ( auto v : edge[now] )
	{
		if ( v == fa || vis[v] )
			continue;
		
		Get_Size(v, now);
		siz[now] += siz[v];
	}
	return;
}

void Get_Root ( int now, int fa, int sum )
{
	bool is_root = true;
	for ( auto v : edge[now] )
	{
		if ( v == fa || vis[v] )
			continue;
		
		Get_Root(v, now, sum);
		if ( siz[v] > sum >> 1 )
			is_root = false;
	}
	if ( sum - siz[now] > sum >> 1 )
		is_root = false;

	if ( is_root )
		root = now;
	return;
}

void Get_Point ( int now, int fa )
{
	point[++cnt] = now;
	for ( auto v : edge[now] )
	{
		if ( v == fa || vis[v] )
			continue;
		Get_Point(v, now);
	}
	return;
}

void Update ( int now, int fa, int id )
{
	int pre = Tree.Query(id, a[now]), up = Tree.Query_Suffix(id, a[now] + 1) + 1;
	if ( ans[now] < cnt )
		ans[now] = max(ans[now], Tree.Query_Suffix(id, a[now] + 1) + 1);
	if ( up > pre )
		Tree.Insert(id, a[now], up);
	
	for ( auto v : edge[now] )
	{
		if ( v == fa || vis[v] )
			continue;
		
		Update(v, now, id);
	}
	if ( up > pre )
		Tree.Change(id, a[now], pre);
	return;
}

void Insert ( int now, int fa )
{
	Tree.root[now] = 0;
	
	for ( auto v : edge[now] )
	{
		if ( v == fa || vis[v] )
			continue;
		
		Insert(v, now);
		Tree.Merge(now, v);
	}
	
	int up = Tree.Query_Suffix(now, a[now] + 1) + 1;
	Tree.Insert(now, a[now], up);
	return;
}

void Dfs ( int now )
{
	cnt = 0;
	Get_Point(now, 0);
	for ( int i = 1; i <= cnt; i ++ )
		save[i] = a[point[i]];
	sort(save + 1, save + 1 + cnt);
	len = unique(save + 1, save + 1 + cnt) - ( save + 1 );
	for ( int i = 1; i <= cnt; i ++ )
		a[point[i]] = lower_bound(save + 1, save + 1 + len, a[point[i]]) - save;
	
	vis[now] = true;
	int son = edge[now].size() - 1;

	Tree.Clear();
	Tree.root[now] = 0;
	Tree.Insert(now, a[now], 1);

	for ( int i = 0; i <= son; i ++ )
	{
		int v = edge[now][i];
		if ( vis[v] )
			continue;
		
		Update(v, now, now);
		if ( i < son )
		{
			Insert(v, now);
			Tree.Merge(now, v);
			int up = Tree.Query_Suffix(now, a[now] + 1) + 1;
			Tree.Insert(now, a[now], up);
		}
	}
	
	Tree.Clear();
	Tree.root[now] = 0;
	Tree.Insert(now, a[now], 1);
	
	for ( int i = son; i >= 0; i -- )
	{
		int v = edge[now][i];
		if ( vis[v] )
			continue;
		
		Update(v, now, now);
		Insert(v, now);
		Tree.Merge(now, v);
		int up = Tree.Query_Suffix(now, a[now] + 1) + 1;
		Tree.Insert(now, a[now], up);
	}
	
	if ( ans[now] < cnt )
		ans[now] = max(ans[now], Tree.Query(now, a[now]));
	for ( int i = 0; i <= son; i ++ )
	{
		int v = edge[now][i];
		if ( vis[v] )
			continue;
		
		Get_Size(v, now);
		Get_Root(v, now, siz[v]);
		Dfs(root);
	}
	return;
}

int main ()
{
	freopen("lot.in", "r", stdin);
	freopen("lot.out", "w", stdout);
	scanf("%d", &n);
	for ( int i = 1; i <= n; i ++ )
		scanf("%d", &a[i]);
	for ( int i = 2, u, v; i <= n; i ++ )
	{
		scanf("%d%d", &u, &v);
		edge[u].push_back(v);
		edge[v].push_back(u);
	}

	Get_Size(1, 0);
	Get_Root(1, 0, siz[1]);
	Dfs(root);

	cerr << cnt_merge << endl;
	cerr << cnt_insert << endl;
	cerr << cnt_change << endl;
	cerr << cnt_query << endl;

	for ( int i = 1; i <= n; i ++ )
		printf("%d\n", ans[i]);
	return 0;
}

T3 海盗

设当前节点为 \(i\) ,设当前节点传递 \(x\) 个金币给上一个节点,当前节点收到了下一个节点的 \(y\) 个金币( \(x,y\) 可以为正数,可以为负数),显然当前节点的金币数为 \(a_i-x+y\) ,那么有:

\[L_i\le a_i-x+y\le R_i\\ L_i-a_i+x\le y\le R_i-a_i+x \]

如果我们可以确定 \(x\) ,那么 \(y\) 的范围也就确定了。

有一种比较显然的 dp 思路,设 \(f_{i,j}\) 表示考虑到第 \(i\) 个人,第 \(i+1\) 个人传递给第 \(i\) 个人 \(j\) 个硬币时的最小代价,显然转移有:

\[f_{i,j}=\min_{k=L_i-a_i}^{R_i-a_i}(f_{i-1,j-k})+|j| \]

由于转移构成环,因此考虑枚举第 \(1\) 个人传递给第 \(n\) 个人的金币数 \(x\) ,此时可以得到一种 \(O((\sum a_i)^3)\) 的暴力 dp 做法。

考虑进行优化,设函数 \(f_i(x)=f_{i,x}\) ,此时证明 \(f_i(x)\) 关于 \(x\) 构成一个下凸函数。

考虑归纳法进行证明,首先对于 \(f_0(x)\) ,这显然成立。

考虑过程中的转移,首先存在一种取 \(\min\) 操作,假设 \(f_{i-1}(x)\) 是下凸函数,并且 \(mid\) 为该函数最低点,不放令 \(L_i-a_i\to L_i,R_i-a_i\to R_i\) ,那么考虑一下几种情况:

  1. \(x-R_i\ge mid\) ,显然 \(f_i(x)=f_{i-1}(x-R_i)\) ;

  2. \(x-L_i\le mid\) ,显然 \(f_i(x)=f_{i-1}(x-L_i)\) ;

  3. \(x-R_i<mid<x-L_i\) ,此时 \(x\) 的转移范围包含 \(mid\) ,显然 \(f_i(x)=f_{i-1}(mid)\) 。

考虑形象化表示转移,将 \(f_{i-1}(x)\) 从 \(mid\) 处一分为二,左半部分向右平移 \(L_i\) ,右半部分向右平移 \(R_i\) ,中间部分使用函数最低点填平,显然操作过后,函数仍然为下凸函数。

由于 \(|x|\) 也是下凸函数,因此函数叠加后仍然是下凸函数。

实际上根据上述分析, \(f_i(x)\) 只需要维护两种操作,就可以进行转移:函数平移,叠加 \(|x|\) 。

考虑 slope trick ,维护一个对顶堆,左堆维护函数最低点向左的信息,右堆维护函数最低点向右的信息,左堆内从大到小第 \(i\) 个权值 \(x\) 表示函数在位置 \(x\) 斜率由 \(1-i\) 变为 \(-i\) ,右堆内从小到大第 \(i\) 个权值 \(x\) 表示函数在位置 \(x\) 斜率由 \(i-1\) 变为 \(i\) ,维护变量 \(min\_val\) 表示函数最低点的值。

考虑修改,对于函数平移,显然直接维护 lazy 标记即可。

对于叠加 \(|x|\) ,大致分以下三种情况考虑:

左堆 \(top\) \(\le 0\le\) 右堆 \(top\) ,发现此时左堆斜率减 \(1\) ,右堆斜率加 \(1\) ,因此直接分别在两个堆中插入位置 \(0\) 即可。

左堆 \(top\) \(>0\) ,此时左堆斜率由 \(0\) 变为 \(-1\) 的转折点变为斜率由 \(1\) 变为 \(0\) 的转折点,因此取出左堆内最大元素插入到右堆中并将其在左堆中删除,考虑位置 \(0\) 前后斜率相差 \(2\) ,因此在左堆内插入两个 \(0\) 即可。

右堆 \(top\) \(<0\) ,显然与左堆 \(top\) \(>0\) 同理。

于是我们可以在 \(O(n\log n)\) 的时间复杂度内完成转移。

继续考虑优化,设 \(g(x)\) 为第 \(1\) 个节点传递给第 \(n\) 个节点 \(x\) 个金币时的最小代价,通过打表发现 \(g(x)\) 是一个单谷函数,因此可以三分求解。

简单进行证明,我们需要证明的东西等价于 \(\tfrac{g(P)+g(Q)}{2}\ge g(\tfrac{P+Q}{2})\) 。

考虑将定义域扩展到实数,不难发现答案与整数相同。

设 \(p_i,q_i\) 分别为最小代价是第 \(i\) 个节点传递给上一个节点的金币个数,考虑构造 \(r_i=\tfrac{p_i+q_i}{2}\) ,由于 \(L_i\le p_i,q_i\le R_i\) ,因此 \(L_i\le r_i\le R_i\) ,因此 \(r\) 序列一定合法,由于 \(|\tfrac{p_i+q_i}{2}|\le |\tfrac{p_i}{2}|+|\tfrac{q_2}{2}|\) ,因此 \(r\) 序列所对应的答案 \(\le \tfrac{g(P)+g(Q)}{2}\) ,显然 \(r\) 序列的对应的答案 \(\ge g(\tfrac{P+Q}{2})\) ,因此结论成立。

code

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int max1 = 2e5;
const long long inf = 0x3f3f3f3f3f3f3f3f;
int n, L[max1 + 5], R[max1 + 5], sum;
struct Top_Queue
{
	long long lazyL, lazyR, min_val;
	priority_queue < long long, vector <long long>, less <long long> > queL;
	priority_queue < long long, vector <long long>, greater <long long> > queR;
	void Clear ()
	{
		lazyL = lazyR = min_val = 0;
		while ( !queL.empty() )
			queL.pop();
		while ( !queR.empty() )
			queR.pop();
		return;
	}
	void Build ( long long x )
	{
		Clear();
		for ( int i = 1; i <= n + 20; i ++ )
			queL.push(x);
		for ( int i = 1; i <= n + 20; i ++ )
			queR.push(x);
		return;
	}
	void MoveL ( long long x )
		{ lazyL += x; return; }
	void MoveR ( long long x )
		{ lazyR += x; return; }
	long long TopL ()
		{ return queL.top() + lazyL; }
	long long TopR ()
		{ return queR.top() + lazyR; }
	void InsertL ( long long x )
		{ return queL.push(x - lazyL); }
	void InsertR ( long long x )
		{ return queR.push(x - lazyR); }
	void DeleteL ()
		{ return queL.pop(); }
	void DeleteR ()
		{ return queR.pop(); }
	void Add ()
	{
		if ( TopL() > 0 )
		{
			InsertR(TopL());
			min_val += abs(TopL());
			DeleteL();
			InsertL(0);
			InsertL(0);
		}
		else if ( TopR() < 0 )
		{
			InsertL(TopR());
			min_val += abs(TopR());
			DeleteR();
			InsertR(0);
			InsertR(0);
		}
		else
		{
			InsertL(0);
			InsertR(0);
		}
		return;
	}
	long long Query ( long long x )
	{
		long long ans = min_val;
		if ( TopL() > x )
		{
			long long cnt = 1;
			while ( TopL() > x )
			{
				long long now = TopL();
				DeleteL();
				ans += cnt * ( now - max(x, TopL()) );
				++cnt;
			}
		}
		else if ( TopR() < x )
		{
			long long cnt = 1;
			while ( TopR() < x )
			{
				long long now = TopR();
				DeleteR();
				ans += cnt * ( min(x, TopR()) - now );
				++cnt;
			}
		}
		return ans;
	}
}Top;
long long Solve ( long long x )
{
	Top.Build(x);
	for ( int i = 1; i <= n; i ++ )
	{
		Top.MoveR(R[i]);
		Top.MoveL(L[i]);
		Top.Add();
	}
	return Top.Query(x);
}
int main ()
{
	freopen("pirate.in", "r", stdin);
	freopen("pirate.out", "w", stdout);
	scanf("%d", &n);
	for ( int i = 1, w; i <= n; i ++ )
	{
		scanf("%d%d%d", &w, &L[i], &R[i]);
		sum += w;
		L[i] = L[i] - w;
		R[i] = R[i] - w;
	}

	long long L = -sum, R = sum, ans = inf;
	while ( R - L > 5 )
	{
		long long mid = L + R >> 1;
		long long ansL = Solve(mid), ansR = Solve(mid + 1);
		ans = min(ans, ansL);
		ans = min(ans, ansR);
		if ( ansL < ansR )
			R = mid - 1;
		else
			L = mid + 1;
	}
	for ( long long i = L; i <= R; i ++ )
		ans = min(ans, Solve(i));
	printf("%lld\n", ans);
	return 0;
}

标签:cnt,val,int,ans,long,清北营,冲刺,2023,now
From: https://www.cnblogs.com/KafuuChinocpp/p/17363287.html

相关文章

  • 每日总结2023-04-28
    今天完成了ANdroid中的找回密码packagecom.example.math;/**找回界面*/importstaticandroid.widget.Toast.LENGTH_SHORT;importandroidx.appcompat.app.AppCompatActivity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.view.View;import......
  • 2023 4 28
     ......
  • 2023-04-28:将一个给定字符串 s 根据给定的行数 numRows 以从上往下、从左到右进行 Z
    2023-04-28:将一个给定字符串s根据给定的行数numRows以从上往下、从左到右进行Z字形排列比如输入字符串为"PAYPALISHIRING"行数为3时,排列如下PAHNAPLSIIGYIR之后,你的输出需要从左往右逐行读取,产生出一个新的字符串"PAHNAPLSIIGYIR"请你实现......
  • 2023/4/28
    R6-2复数的加减运算(运算符重载)分数 30全屏浏览题目作者 fpc单位 内蒙古师范大学###复数加减(运算符重载)声明一个复数类CComplex(类私有数据成员为double型的real和image)定义构造函数,用于指定复数的实部与虚部。重载<<运算符,以格式real+imagei的格......
  • 【考后总结】NOI 统一省选 2023
    文化课补完了,但是考试考炸了,所以来补题。D1T1火车站station实际上只需要判断从\(x\)能否一直向一个方向移动且每个位置能不能作为这个方向的终点站。区间覆盖差分一下即可。提交记录:Submission-QOJD1T2城市建造cities一个连通块中只能有一个点被选中。由于连通块大......
  • 【考后总结】NOI 统一省选 2023
    文化课补完了,但是考试考炸了,所以来补题。D1T1火车站station实际上只需要判断从\(x\)能否一直向一个方向移动且每个位置能不能作为这个方向的终点站。区间覆盖差分一下即可。提交记录:Submission-QOJD1T2城市建造cities一个连通块中只能有一个点被选中。由于连通块大......
  • 【考后总结】NOI 统一省选 2023
    文化课补完了,但是考试考炸了,所以来补题。D1T1火车站station实际上只需要判断从\(x\)能否一直向一个方向移动且每个位置能不能作为这个方向的终点站。区间覆盖差分一下即可。提交记录:Submission-QOJD1T2城市建造cities一个连通块中只能有一个点被选中。由于连通块大......
  • 【考后总结】NOI 统一省选 2023
    文化课补完了,但是考试考炸了,所以来补题。D1T1火车站station实际上只需要判断从\(x\)能否一直向一个方向移动且每个位置能不能作为这个方向的终点站。区间覆盖差分一下即可。提交记录:Submission-QOJD1T2城市建造cities一个连通块中只能有一个点被选中。由于连通块大......
  • 【考后总结】NOI 春季测试 2023
    文化课补完了,所以来改题。T1涂色paint弱智签到题,维护时间戳。Submission-洛谷T2幂次power近似原题:CodeForces-955CSadPowers*2100一个数可能会被统计多次,例如\(2^{12}=4^6=8^4=16^3=64^2\),考虑只在\(2^{12}\),即指数最大的位置记录答案,由于\(1\)比较特殊先不考......
  • 2023.4.28——软件工程日报
    所花时间(包括上课):6h代码量(行):0行博客量(篇):1篇今天,上午学习,下午学习并开会。我了解到的知识点:1.了解了一些数据库的知识;2.了解了一些python的知识;3.了解了一些英语知识;5.了解了一些Javaweb的知识;4.了解了一些数学建模的知识;6.了解了一些计算机网络的知识;......