2022NOIP A层联测27

A. 天平

发现是求最少用多少数,使得他们的 \(gcd\) 为整个序列所有数的 \(gcd\)

因为一个数不停取 \(gcd\) 最多就 \(log\), 直接开 \(map\) 转移即可

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 = 55;
int a[maxn], g, n;
map<int, int> mp;
int main(){
	freopen("weights.in","r",stdin);
	freopen("weights.out","w",stdout);
	n = read();
	for(int i = 1; i <= n; ++i)a[i] = read();
	g = a[1];
	for(int i = 2; i <= n; ++i)g = __gcd(g, a[i]);
	for(int i = 1; i <= n; ++i){
		mp[a[i]] = 1;
		for(auto x : mp){
			int to = __gcd(x.first, a[i]);
			if(mp[to] == 0 || mp[to] > x.second + 1)mp[to] = x.second + 1;
		}
	}
	printf("%d\n",mp[g]);
	return 0;
}

B. 支配数据

树套树

\(n\) 个数用一颗线段树维护,动态开点,没有点的看成初始值,比较方便的办法是用类似主席树的思想

外层一棵线段树维护区间覆盖的标记,和整区间最小值

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 = 100005;
int b[maxn], n, k, root[maxn];

struct seg{
	struct node{
		int l, r, val;
		bool tag;
	}t[maxn * 160];
	int cnt, c0;
	void push_up(int x){t[x].val = min(t[t[x].l].val, t[t[x].r].val);}
	void upd(int x, int val){t[x].val = val; t[x].tag = true;}
	void push_down(int x){
		if(t[x].l <= c0)t[x].l = ++cnt;
		if(t[x].r <= c0)t[x].r = ++cnt;
		upd(t[x].l, t[x].val);
		upd(t[x].r, t[x].val);
		t[x].tag = false;
	}
	int built(int l, int r){
		int now = ++cnt;
		if(l == r){t[now].val = b[l];return now;}
		int mid = (l + r) >> 1;
		t[now].l = built(l, mid);
		t[now].r = built(mid + 1, r);
		push_up(now); return now;
	}	
	int modify(int x, int l, int r, int L, int R, int val){
		int now = x; if(now <= c0)now = ++cnt, t[now] = t[x], t[now].tag = 0;
		if(L <= l && r <= R){upd(now, val);return now;}
		if(t[x].tag)push_down(x);
		int mid = (l + r) >> 1;
		if(L <= mid)t[now].l = modify(t[x].l, l, mid, L, R, val);
		if(R > mid)t[now].r = modify(t[x].r, mid + 1, r, L, R, val);
		push_up(now); return now;
	}
	int query(int x, int l, int r, int L, int R){
		if(L <= l && r <= R)return t[x].val;
		if(t[x].tag)push_down(x);
		int mid = (l + r) >> 1, ans = INT_MAX;
		if(L <= mid)ans = min(ans, query(t[x].l, l, mid, L, R));
		if(R > mid)ans = min(ans, query(t[x].r, mid + 1, r, L, R));
		return ans;
	}
}t;
struct segmi{
	struct node{
		int val, tag;
	}t[maxn << 2 | 1];
	void upd(int x, int val){t[x].val = t[x].tag = val;}
	void push_up(int x){t[x].val = min(t[x << 1].val, t[x << 1 | 1].val);}
	void push_down(int x){upd(x << 1, t[x].val); upd(x << 1 | 1, t[x].val); t[x].tag = 0;}
	void built(int x, int l, int r, int val){
		t[x].val = val; t[x].tag = 0;
		if(l == r)return;
		int mid = (l + r) >> 1;
		built(x << 1, l, mid, val);
		built(x << 1 | 1, mid + 1, r, val);
	}
	void modify(int x, int l, int r, int L, int R, int val){
		if(L <= l && r <= R){upd(x, val); return;}
		if(t[x].tag)push_down(x);
		int mid = (l + r) >> 1;
		if(L <= mid)modify(x << 1, l, mid, L, R, val);
		if(R > mid)modify(x << 1 | 1, mid + 1, r, L, R, val);
		push_up(x);
	}
	void modify_one(int x, int l, int r, int pos, int val){
		if(l == r){
			t[x].val = val;
			t[x].tag = 0;
			return;
		}
		if(t[x].tag)push_down(x);
		int mid = (l + r) >> 1;
		if(pos <= mid)modify_one(x << 1, l, mid, pos, val);
		else modify_one(x << 1 | 1, mid + 1, r, pos, val);
		push_up(x);
	}
	int query(int x, int l, int r, int L, int R){
		if(L <= l && r <= R)return t[x].val;
		if(t[x].tag)push_down(x);
		int mid = (l + r) >> 1, ans = INT_MAX;
		if(L <= mid)ans = min(ans, query(x << 1, l, mid, L, R));
		if(R > mid)ans = min(ans, query(x << 1 | 1, mid + 1, r, L, R));
		return ans;
	}
	int query(int x, int l, int r, int pos){
		if(l == r)return t[x].tag;
		if(t[x].tag)push_down(x);
		int mid = (l + r) >> 1;
		if(pos <= mid)return query(x << 1, l, mid, pos);
		else return query(x << 1 | 1, mid + 1, r, pos);
	}
}T;
void modify(int l, int r){
	int x = read();
	int L = (l + n - 1) / n;
	int R = (r + n - 1) / n;
	if(L + 1 <= R - 1)T.modify(1, 1, k, L + 1, R - 1, x);
	int ql = T.query(1, 1, k, L); int qr = T.query(1, 1, k, R);
	if(ql)root[L] = t.modify(root[L], 1, n, 1, n, ql);
	if(qr)root[R] = t.modify(root[R], 1, n, 1, n, qr);
	l = (l - 1) % n + 1; r = (r - 1) % n + 1;
	if(L != R){
		root[L] = t.modify(root[L], 1, n, l, n, x);
		root[R] = t.modify(root[R], 1, n, 1, r, x);
		ql = t.query(root[L], 1, n, 1, n);
		qr = t.query(root[R], 1, n, 1, n);
		T.modify_one(1, 1, k, L, ql);
		T.modify_one(1, 1, k, R, qr);
	}else{
		root[L] = t.modify(root[L], 1, n, l, r, x);
		ql = t.query(root[L], 1, n, 1, n);
		T.modify_one(1, 1, k, L, ql);
	}
}
int query(int l, int r){
	int L = (l + n - 1) / n;
	int R = (r + n - 1) / n;
	int ans = INT_MAX;
	if(L + 1 <= R - 1)ans = T.query(1, 1, k, L + 1, R - 1);
	int ql = T.query(1, 1, k, L);
	int qr = T.query(1, 1, k, R);
	if(ql)root[L] = t.modify(root[L], 1, n, 1, n, ql);
	if(qr)root[R] = t.modify(root[R], 1, n, 1, n, qr);
	l = (l - 1) % n + 1; r = (r - 1) % n + 1;
	if(L != R){
		ans = min(ans, t.query(root[L], 1, n, l, n));
		ans = min(ans, t.query(root[R], 1, n, 1, r));
	}else ans = min(ans, t.query(root[L], 1, n, l, r));
	return ans;
}
int main(){
	//freopen("data.in","r",stdin);
	//freopen("data.out","w",stdout);
	n = read(), k = read();
	for(int i = 1; i <= n; ++i)b[i] = read();
	root[1] = t.built(1, n); for(int i = 2; i <= k; ++i)root[i] = root[1];
	T.built(1, 1, k, t.query(root[1], 1, n, 1, n)); t.c0 = t.cnt;
	int q = read();
	for(int i = 1; i <= q; ++i){
		int op = read(), l = read(), r = read();
		if(op & 1) modify(l, r);
		else printf("%d\n",query(l, r));
	}
	return 0;
}

C. 信息学的尽头

基环树 \(DP\)

肯定先把环找出来

拆掉环边考虑当前子树

子树内贡献简单的换根 \(DP\)

如何处理子树外的

考虑他们肯定要先到当前根节点,于是处理这个,然后就是简单的统计答案了

考虑在环上,依次考虑每个点,其他点到他肯定一侧顺时针一侧逆时针,那么就存在一个分界点,而随着当前点的顺序移动,分界点一定只会同向移动,于是使用双指针即可

考场调不出来,于是在环上爆扫,因为数据水过了

现在是正确的

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 = 200005;
const ll inf = 0x3f3f3f3f3f3f3f3f;
typedef pair<int, int> pii;
struct DSU{
	int f[maxn];
	void init(int x){for(int i = 1; i <= x; ++i)f[i] = i;}
	int fa(int x){return x == f[x] ? x : f[x] = fa(f[x]);}
	bool merge(int u, int v){u = fa(u); v = fa(v); if(u == v)return false; f[u] = v; return true;}
}UN;
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;
}
int n;
bool in[maxn];
int fa[maxn];
ll rval[maxn], ans[maxn];
vector<pii>vec;
void prefind(int x){
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to; if(v == fa[x])continue;
		fa[v] = x; rval[v] = e[i].val; prefind(v);
	}
}
void tag(int u){while(fa[u]){in[u] = true; vec.push_back(pii(u, rval[u])); u = fa[u];}in[u] = true;}
int siz[maxn];
void dfs(int x){
	siz[x] = 1; rval[x] = 0;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(in[v] || v == fa[x])continue;
		fa[v] = x;
		dfs(v);
		siz[x] += siz[v];
		rval[x] += rval[v];
		rval[x] += 1ll * siz[v] * e[i].val;
	}
}
int S;
void sol(int x){
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(in[v] || v == fa[x])continue;
		rval[v] = rval[x] + 1ll * (S - siz[v] - siz[v]) * e[i].val;
		sol(v);
	}
}
void modify(int x, ll val, int S, ll dis){
	ans[x] += val + S * dis;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(in[v] || v == fa[x])continue;
		modify(v, val, S, dis + e[i].val);
	}
}
ll dis[maxn + maxn], sdis[maxn + maxn];
int si[maxn + maxn], ss[maxn + maxn], sp[maxn];
ll g[maxn + maxn];
int main(){
	freopen("end.in","r",stdin);
	freopen("end.out","w",stdout);
	n = read(); UN.init(n);
	for(int i = 1; i <= n; ++i){
		int u = read(), v = read(), w = read();
		if(UN.merge(u, v) == false){prefind(u); vec.push_back(pii(u, w)); tag(v);}
		add(u, v, w); add(v, u, w);
	}
	for(int i = 1; i <= n; ++i)fa[i] = 0;
	for(pii x : vec){dfs(x.first); S = siz[x.first]; sol(x.first);}
	for(int i = 1; i <= n; ++i)ans[i] = rval[i];
	ll sval = 0; int cnt = 0;
	for(pii x : vec){
		sval += rval[x.first];
		si[++cnt] = siz[x.first];
		dis[cnt] = x.second;
	}
	for(int i = 1; i <= cnt; ++i)si[i + cnt] = si[i], dis[i + cnt] = dis[i];
	for(int i = 1; i <= cnt + cnt; ++i)sdis[i] = sdis[i - 1] + dis[i], ss[i] = ss[i - 1] + si[i];
	for(int i = 1; i <= cnt + cnt; ++i)g[i] = g[i - 1] + si[i] * sdis[i - 1];
	int p = 1;
	for(int i = 1; i <= cnt; ++i){
		while(p < i + cnt && sdis[p] - sdis[i - 1] < sdis[i + cnt - 1] - sdis[p])++p;
		sp[i] = p;
	}
	for(int i = 1; i <= cnt; ++i){
		int now = vec[i - 1].first;
		ll dt = sval - rval[now];
		if(sp[i] > i)dt += g[sp[i]] - g[i] - sdis[i - 1] * (ss[sp[i]] - ss[i]);
		if(sp[i] < i + cnt - 1) dt += - g[i + cnt - 1] + g[sp[i]] + sdis[i + cnt - 1] * (ss[i + cnt - 1] - ss[sp[i]]);
		modify(now, dt, n - si[i], 0);
	}
	for(int i = 1; i <= n; ++i)printf("%lld ", ans[i]);
	printf("\n");
	return 0;
}

D. 球对称薛定谔方程

神奇 \(DP\)

\(AGC024E\) 题解看洛谷吧。

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

using namespace std;

typedef long long ll;
typedef unsigned long long ull;


const int maxn = 305;
int n, k, mod;
int f[maxn][maxn][maxn];
void add(int &x, int y){x += y; x = x >= mod ? x - mod : x;}
int main(){
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	cin >> n >> k >> mod;
	f[0][1][0] = 1;
	for(int i = 0; i <= n; ++i){
		for(int j = 1; j <= k; ++j){
			for(int p = i; p >= 1; --p)add(f[i][j][p - 1], f[i][j][p]);
			add(f[i][j + 1][i], f[i][j][0]);
			for(int p = 0; p <= i; ++p)add(f[i + 1][j][p], 1ll * (p + 1) * f[i][j][p] % mod);
		}
	}	
	cout << f[n][k][0] << endl;
	return 0;
}

posted @ 2022-11-13 17:56  Chen_jr  阅读(13)  评论(0编辑  收藏  举报