2022NOIP A层联测11

A. 小 h 的几何

最后式子化成了 (A+B+C)/2 不会证

code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}
const int maxn = 500005;
const double PI = acos(-1);
struct node{double x, y;}d[maxn];
int n;
double ax, ay;
int main(){
	freopen("geometry.in","r",stdin);
	freopen("geometry.out","w",stdout);
	n = read();
	for(int i = 1; i <= n; ++i){
		double the = read() / 1e9 * PI;
		d[i] = {cos(the), sin(the)};
	}
	for(int i = 1; i <= n; ++i){
		ax += d[i].x * (n - 1) * (n - 2) / 4;
		ay += d[i].y * (n - 1) * (n - 2) / 4;
	}
	double num = 6.0 / ((double)n * (double)(n - 1) * (n - 2));
	printf("%.15lf %.15lf\n",ax * num, ay * num);
	return 0;
}

B. 小 w 的代数

一个树形 DP 是每次考虑从当前根节点出发的所有链的方案数, fi,j 表示到 i 节点,链尾元素为 j 的方案数

考虑怎么在一个简单环上做

从进入环上的点开始,顺时针逆时针分两次对环上的点进行转移,考虑一旦在转的过程中选定了一个点,那么转移的方向是确定的,即在环上选了非入/出环的点,那么两次转移是没有交的

于是只用考虑直接从入点到出点的被多计算了一次,在出点处对应减去其贡献即可

在处理时为了方便,我们建立圆方树,圆点统计答案,方点进行转移

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}

const int maxn = 1005;
const int mod = 998244353;
int n, m;
int head[maxn], tot;
struct edge{int to, net;}e[maxn << 2 | 1];
void link(int u, int v){
	e[++tot].net = head[u];
	head[u] = tot;
	e[tot].to = v;
}
vector<int>g[maxn];
int low[maxn], dfn[maxn], sta[maxn], top, tim, cnt;
void tarjan(int x, int fa){
	sta[++top] = x;
	low[x] = dfn[x] = ++tim;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(!dfn[v]){
			tarjan(v, x);
			low[x] = min(low[x], low[v]);
			if(low[v] == dfn[x]){
				++cnt; int now;
				do{
					now = sta[top--];
					g[now].push_back(cnt + n);
					g[cnt + n].push_back(now);
				}while(now != v);
				g[x].push_back(cnt + n);
				g[cnt + n].push_back(x);
			}
		}else low[x] = min(low[x], dfn[v]);
	}
}
int f[maxn][maxn], tmp[maxn], ans, fir;
vector<int>node;
void add(int &x, int y){x += y; x = x >= mod ? x - mod : x;}
void dfs(int x, int fa){
	if(x <= n){
		for(int i = fir; i < x; ++i)add(ans, f[x][i]);
		for(int i = fir; i < x; ++i)add(f[x][x], f[x][i]);
	}else{
		int pf, s = g[x].size();
		for(int i = 0; i < s; ++i)if(g[x][i] == fa){pf = i; break;}
		node.clear();
		for(int i = (pf + 1) % s; i != pf; i = (i + 1) % s)node.push_back(g[x][i]);
		for(int i = fir; i <= n; ++i)tmp[i] = f[fa][i];
		for(int v : node){
			for(int i = fir; i <= n; ++i)add(f[v][i], tmp[i]);
			for(int i = fir; i < v; ++i)add(tmp[v], tmp[i]);
		}
		for(int i = fir; i <= n; ++i)tmp[i] = f[fa][i];
		reverse(node.begin(), node.end());
		for(int v : node){
			for(int i = fir; i <= n; ++i)add(f[v][i], tmp[i]);
			for(int i = fir; i < v; ++i)add(tmp[v], tmp[i]);		
		}
		for(int v : node)
			for(int i = fir; i <= n; ++i)add(f[v][i], mod - f[fa][i]);
	}
	for(int v : g[x])if(v != fa)dfs(v, x);
}
int main(){
	freopen("algebra.in","r",stdin);
	freopen("algebra.out","w",stdout);
	n = read(), m = read();
	for(int i = 1; i <= m; ++i){
		int u = read(), v = read();
		link(u, v); link(v, u);
	}
	tarjan(1, 1);
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= n; ++j)
			for(int k = 1; k <= n; ++k)
				f[j][k] = 0;
		f[i][i] = 1;
		fir = i;
		dfs(i, i);
	}
	add(ans, n);
	printf("%d\n",ans);
	return 0;
}

C. 小 y 的数论

一个点集的最优解,可以建出虚树,然后长链剖分,取前 k 大的链

大区间的最优解一定产生在含于他的小区间的最优解中

于是每次合并可以只对 2k 个点处理

按照 k 进行分块,每 k 个看成一个元素建立 ST

查询处理两边散块和中间查询的整块

代码是褐的

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, ll> pil;

#define gc if(++ip==ie)fread(ip=buf,1,SZ,stdin)
const int SZ=1<<20;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int read(){
	gc;while(*ip<'-')gc;
	bool f=*ip=='-';if(f)gc;
	int x=*ip&15;gc;
	while(*ip>'-'){x*=10;x+=*ip&15;gc;}
	return f ? -x : x;
}
const int maxn = 300005, mlg = 20, mk = 100, bk = maxn / 100 + 15;
int n, q, lg[maxn];

int head[maxn], tot;
struct edge{int to, net, val;}e[maxn << 1 | 1];
void add(int u, int v, int w){
	e[++tot].net = head[u];
	head[u] = tot;
	e[tot].to = v;
	e[tot].val = w;
}
ll sum[maxn];
int lst[maxn][mlg], dfn[maxn], dep[maxn], fa[maxn], tim;
void pre(int x){
	dfn[x] = ++tim;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(v == fa[x])continue;
		fa[v] = x; dep[v] = dep[x] + 1;
		sum[v] = sum[x] + e[i].val;
		pre(v);
	}
}
int cmpare(int x, int y){return dep[x] < dep[y] ? x : y;}
void init(){
	pre(1);
	for(int i = 1; i <= n; ++i)lst[dfn[i]][0] = fa[i];
	for(int j = 1; j <= lg[n]; ++j)
		for(int i = 1; i + (1 << j) - 1 <= n; ++i)
			lst[i][j] = cmpare(lst[i][j - 1], lst[i + (1 << (j - 1))][j - 1]);
}
int lca(int u, int v){
	if(u == v)return u;
	u = dfn[u]; v = dfn[v];
	if(u > v)swap(u, v);
	++u; int k = lg[v - u + 1];
	return cmpare(lst[u][k], lst[v - (1 << k) + 1][k]);
}
ll dis(int u, int v){int lc = lca(u, v); return sum[u] + sum[v] - sum[lc] - sum[lc];}

vector <pil> g[maxn];
void link(int u, int v, ll w){g[u].push_back({v, w}); g[v].push_back({u, w});}
bool cmp(int x, int y){return dfn[x] < dfn[y];}
pil dfs(int x, int fa, vector<pil>&vec){
	pil now = pil(x, 0);
	for(pil v : g[x]){
		if(v.first == fa)continue;
		pil k = dfs(v.first, x, vec);
		k.second += v.second;
		if(now.second < k.second){
			if(now.second)vec.push_back(now);
			now = k;
		}else vec.push_back(k);
	}
	return now;
}
bool cp(pil x, pil y){return x.second > y.second;}
struct node{
	vector<int>nd;
	vector<ll>val;
	friend node operator + (const node &x, const node &y){
		node ans;
		vector<int>v;
		v.resize(x.nd.size() + y.nd.size());
		merge(x.nd.begin(), x.nd.end(), y.nd.begin(), y.nd.end(), v.begin(), cmp);
		v.erase(unique(v.begin(), v.end()), v.end());
		if(v.size() == 1){swap(ans.nd, v);return ans;}
		
		int sta[maxn], top;
		int root = sta[top = 1] = v[0]; g[sta[1]].clear();
		for(int i : v){
			if(i == v[0])continue;
			int lc = lca(i, sta[top]);
			while(top >= 2 && dep[sta[top - 1]] >= dep[lc]){
				link(sta[top - 1], sta[top], sum[sta[top]] - sum[sta[top - 1]]);
				--top;
			}
			if(lc != sta[top]){
				g[lc].clear();
				link(lc, sta[top], sum[sta[top]] - sum[lc]);
				sta[top] = lc;
			}
			sta[++top] = i; g[i].clear();
		}
		for(int i = top; i > 1; --i)link(sta[i], sta[i - 1], sum[sta[i]] - sum[sta[i - 1]]);
		vector<pil>c;
		pil k = dfs(root, 0, c);
		c.push_back(k);

		int rt = 0; ll mx = 0;
		for(pil v : c)if(v.second >= mx){mx = v.second; rt = v.first;}
		c.clear();
		k = dfs(rt, 0, c);
		c.push_back(k);
		sort(c.begin(), c.end(), cp);
		ll sm = 0;
		ans.nd.push_back(rt);
		ans.val.push_back(0);
		ans.val.push_back(0);
		for(int i = 0; i < mk && i < c.size(); ++i){
			ans.val.push_back(sm += c[i].second);
			ans.nd.push_back(c[i].first);
		}
		sort(ans.nd.begin(), ans.nd.end(), cmp);
		ans.nd.erase(unique(ans.nd.begin(), ans.nd.end()), ans.nd.end());
		return ans;
	}
	void init(int l, int r){
		for(int i = l; i <= r; ++i)nd.push_back(i);
		sort(nd.begin(),nd.end(),cmp);
		(*this) = (*this) + node{};
	}
	ll query(int k){
		if(val.empty())return 0;
		return k < val.size() ? val[k] : val.back();
	}
}st[bk][mlg];
int l[bk], r[bk], block[maxn], len;
int pr[105];
void print(ll x){
	int top = 0;
	while(x){pr[++top] = x % 10; x /= 10;}
	if(top == 0)pr[++top] = 0;
	for(int i = top; i >= 1; --i)putchar('0' + pr[i]);
	putchar('\n');
}
int main(){
	freopen("number.in","r",stdin);
	freopen("number.out","w",stdout);
	n = read();
	for(int i = 1; i < n; ++i){
		int u = read(),v = read(), w = read();
		add(u, v, w); add(v, u, w);
	}
	for(int i = 2; i <= n; ++i)lg[i] = lg[i >> 1] + 1;
	init();
	len = (n - 1) / mk + 1;
	for(int i = 1; i <= len; ++i){
		l[i] = r[i - 1] + 1; r[i] = min(n, i * mk);
		for(int j = l[i]; j <= r[i]; ++j)block[j] = i;
		st[i][0].init(l[i], r[i]);
	}
	for(int j = 1; j <= lg[len]; ++j)
		for(int i = 1; i + (1 << (j - 1)) - 1 <= len; ++i)
			st[i][j] = st[i][j - 1] + st[i + (1 << (j - 1))][j - 1];
	q = read();
	for(int i = 1; i <= q; ++i){
		int ql = read(), qr = read(), qk = read();
		int bl = block[ql], br = block[qr];
		node ans;
		if(bl + 1 >= br)ans.init(ql, qr);
		else{
			node al, ar;
			al.init(ql, r[bl]);
			ar.init(l[br], qr);
			int k = lg[br - bl - 1];
			ans = al + st[bl + 1][k] + st[br - (1 << k)][k] + ar;
		}
		ans.query(qk);
		print(ans.query(qk));
	}
	return 0;
}

D. 小j 的组合

类似 DFS 的过程,每次经过一个点,包括回溯都会统计一下,只有最后走的一条链没有回溯,于是找出直径最后走即可

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}

const int maxn = 105;
int n, head[maxn], tot;
struct edge{int to, net;}e[maxn << 1 | 1];
void add(int u, int v){
	e[++tot].net = head[u];
	head[u] = tot;
	e[tot].to = v;
}
int dep[maxn], son[maxn], md[maxn];

void dfs(int x, int fa){
	md[x] = dep[x];
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(v == fa)continue;
		dep[v] = dep[x] + 1;
		dfs(v, x);
		son[x] = md[son[x]] > md[v] ? son[x] : v;
		md[x] = max(md[x], md[v]);
	}
}
int root;
int top, sta[50005], tim;
void solve(int x, int fa){
	++tim; sta[++top] = x;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(v == fa || v == son[x])continue;
		solve(v, x);
		sta[++top] = x;
	}
	if(son[x]){
		solve(son[x], x);
		if(tim != n)sta[++top] = x;
	}
}
bool vis[maxn];
int main(){
	freopen("combo.in","r",stdin);
	freopen("combo.out","w",stdout);
	n = read();
	for(int i = 1; i < n; ++i){
		int u = read(), v = read();
		add(u, v); add(v, u);
	}
	dep[1] = 0; dfs(1, 0);
	for(int i = 1; i <= n; ++i)root = dep[root] > dep[i] ? root : i;
	for(int i = 1; i <= n; ++i)dep[i] = son[i] = md[i] = 0;
	dep[root] = 0; dfs(root, 0);
	solve(root, 0);
	printf("%d\n",top - n);
	int node = n;
	for(int i = 1; i <= top; ++i)if(vis[sta[i]]){
		printf("%d ",sta[i]);
		sta[i] = ++node;
	}else vis[sta[i]] = true;
	printf("\n");
	for(int i = 1; i <= top; ++i)printf("%d ", sta[i]);
	return 0;
}
posted @   Chen_jr  阅读(78)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示