A
B

NOIP 模拟赛 7

NOIP 模拟赛总结

NOIP 模拟赛 7

dp != 反悔贪心!

T1 Imbalance

淀粉质 + 二维数点 + 容斥

详见 here

密码是:MyShiroko。(不带句号 and 括号)

点击查看代码
#include <stdio.h>
#include <string.h>
#include <bitset>
#include <algorithm>
#define lowbit(x) (x & (-x))
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define add(u,v) to[++ tot] = v,nxt[tot] = h[u],h[u] = tot
#define int long long 
#define Blue_Archive return 0
using namespace std;
constexpr int N = 5e5 + 3;
constexpr int M = 1e6 + 3;
constexpr int INF = 2e9;
 
int T;
int n;
int rt;
int tot;
int ans;
int sum;
int top1;
int top2;
int h[N];
int to[M];
int mx[N];
int tr[N];
int siz[N];
int nxt[M];
 
bitset<N> vis;
 
struct miku
{
	int mx,mn;
	friend bool operator < (miku a,miku b){return a.mx == b.mx ? a.mn > b.mn : a.mx < b.mx;}
}lmx[N],lmn[N];
 
inline int read()
{
	int x = 0;
	int c = getchar_unlocked();
	while(c < '0' || c > '9') c = getchar_unlocked();
	while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48),c = getchar_unlocked();
	return x;
}
 
inline void write(int x)
{
	if(x < 0) x = -x,putchar_unlocked('-');
	if(x > 9) write(x / 10);
	putchar_unlocked(x % 10 + '0');
}
 
inline int max(int x,int y){return x > y ? x : y;}
inline int min(int x,int y){return x < y ? x : y;}
 
inline void ins(int pos,int val){for(int i = pos;i <= n;i += lowbit(i)) tr[i] += val;}
 
inline int query(int pos){int res = 0;for(int i = pos;i;i -= lowbit(i)) res += tr[i];return res;}
 
inline void get(int x,int f)
{
	siz[x] = 1;
	mx[x] = 0;
	for(int i = h[x];i;i = nxt[i])
	{
		if(to[i] == f || vis[to[i]]) continue;
		get(to[i],x);
		siz[x] += siz[to[i]];
		mx[x] = max(mx[x],siz[to[i]]);
	}
	mx[x] = max(mx[x],sum - siz[x]);
	if(mx[x] < mx[rt]) rt = x;
}
 
inline void dfs1(int x,int f,int rt,int mxx,int mnn)
{
	if(x > mxx)
	{
		lmx[++ top1] = miku{mxx = x,mnn};
		ans += (mnn == rt);
	}
	if(x < mnn)
	{
		lmn[++ top2] = miku{mxx,mnn = x};
		ans += (mxx == rt);
	}
	for(int i = h[x];i;i = nxt[i]) if(!vis[to[i]] && to[i] != f) dfs1(to[i],x,rt,mxx,mnn);
}
 
inline void dfs2(int x,int f,int rt,int mxx,int mnn)
{
	if(x > mxx) lmx[++ top1] = miku{mxx = x,mnn};
	if(x < mnn) lmn[++ top2] = miku{mxx,mnn = x};
	for(int i = h[x];i;i = nxt[i]) if(!vis[to[i]] && to[i] != f) dfs2(to[i],x,rt,mxx,mnn);
}
 
inline void dfz(int x) // 淀粉质
{
	vis[x] = 1;
	top1 = top2 = 0;
	for(int i = h[x];i;i = nxt[i]) if(!vis[to[i]]) dfs1(to[i],x,x,x,x);
	sort(lmx + 1,lmx + top1 + 1);
	sort(lmn + 1,lmn + top2 + 1);
	int itl = 1,itr = 1;
	while(itl <= top1 && itr <= top2) // 端点在其子树的两条链上的合法四元组个数(直接上二维偏序)
	{
		if(lmn[itr].mx < lmx[itl].mx) ins(lmn[itr ++].mn,1);
		else ans += query(lmx[itl ++].mn - 1);
	}
	while(itl <= top1)
	{
		if(lmx[itl].mn > 1) ans += query(lmx[itl].mn - 1);
		itl ++;
	} 
	while(-- itr) ins(lmn[itr].mn,-1);
	for(int i = h[x];i;i = nxt[i]) // 容斥子树的贡献
	{
		if(vis[to[i]]) continue;
		top1 = top2 = 0;
		dfs2(to[i],x,x,x,x);
		sort(lmx + 1,lmx + top1 + 1);
		sort(lmn + 1,lmn + top2 + 1);
		int itl = 1,itr = 1;
		while(itl <= top1 && itr <= top2) // 端点在其子树的两条链上的合法四元组个数(直接上二维偏序)
		{
			if(lmn[itr].mx < lmx[itl].mx) ins(lmn[itr ++].mn,1);
			else ans -= query(lmx[itl ++].mn - 1);
		}
		while(itl <= top1)
		{
			if(lmx[itl].mn > 1) ans -= query(lmx[itl].mn - 1);
			itl ++;
		} 
		while(-- itr) ins(lmn[itr].mn,-1);
	}
	for(int i = h[x];i;i = nxt[i])
	{
		if(vis[to[i]]) continue;
		sum = siz[to[i]];
		mx[rt = 0] = INF;
		get(to[i],x);
		get(rt,0);
		dfz(rt);
	}
	vis[x] = 0;
}
 
inline void solve()
{
	n = read();
	for(int i = 1,u,v;i < n;i ++)
	{
		u = read();
		v = read();
		add(u,v);
		add(v,u);
	}
	mx[rt = 0] = INF;
	sum = n;
	get(1,0);
	get(rt,0);
	dfz(rt);
	write(ans);ent;
}
 
signed main()
{
	freopen("imbalance.in","r",stdin);freopen("imbalance.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	solve();
	Blue_Archive;
}

T2 原子

为啥放 T2 ?

简单贪心。

点击查看代码
#include<bits/stdc++.h>
#define int long long 
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define Blue_Archive return 0
using namespace std;
constexpr int N = 5e5 + 3;
constexpr int M = 1e6 + 3;

int n;
int ans;
int top;
int stk[N];

inline int read()
{
	int k = 0,f = 1;
	char c = getchar_unlocked();
	while(c < '0' || c > '9')
	{
		if(c == '-') f = -1;
		c = getchar_unlocked();
	} 
	while(c >= '0' && c <= '9') k = (k << 3) + (k << 1) + c - '0',c = getchar_unlocked();
	return k * f;
}

inline void write(int x)
{
	if(x < 0) putchar_unlocked('-'),x = -x;
	if(x > 9) write(x / 10);
	putchar_unlocked(x % 10 + '0');
}

signed main()
{
	freopen("atom.in","r",stdin);freopen("atom.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	n = read();
	for(int i = 1;i < n;i ++) ans += min(i,n - i);
	write(ans);ent;
	for(int i = 1,k;i < n;i ++)
	{
		for(int j = 0,sum;j < min(i,n - i);j ++)
		{
			top = 0;
			if(j != 0) stk[++ top] = j,sum += j;
			sum = n - 1 - j;
			while(sum >= i)
			{
				sum -= i;
				stk[++ top] = i;
			}
			if(sum) stk[++ top] = sum;
			write(top);con;
			for(int op = 1;op <= top;op ++) write(stk[op]),con;ent;
		}
	}
	Blue_Archive;
}
// 3995002

T3:旅行计划

赛时想写反悔贪心,狂调不止也没调出来qwq

树形DP,考虑三种情况:

  • 到这个点停止的最大贡献。

  • 到这个点出去一条边的最大贡献。

  • 到这个点出去两条边的最大贡献。

直接 DP 即可。

点击查看代码
#include <stdio.h>
#include <string.h>
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define add(u,v,c) to[++ tot] = v,w[tot] = c,nxt[tot] = h[u],h[u] = tot
#define int long long 
#define Blue_Archive return 0
using namespace std;
constexpr int N = 1e6 + 3;
constexpr int M = 2e6 + 3;

int T;
int n;
int tot;
int ans;
int h[N];
int w[M];
int to[M];
int nxt[M];
int dp[N][3];

inline int read()
{
	int x = 0;
	int c = getchar_unlocked();
	while(c < '0' || c > '9') c = getchar_unlocked();
	while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48),c = getchar_unlocked();
	return x;
}

inline void write(int x)
{
	if(x > 9) write(x / 10);
	putchar_unlocked(x % 10 + '0');
}

inline int max(int x,int y){return x > y ? x : y;}
inline int min(int x,int y){return x < y ? x : y;}

inline void dfs(int x,int f)
{
	dp[x][0] = dp[x][1] = dp[x][2] = 0;
	int mx1 = 0,mx2 = 0;
	for(int i = h[x];i;i = nxt[i])
	{
		if(to[i] == f) continue;
		dfs(to[i],x);
		if(w[i] > 1)
		{
			dp[x][0] += dp[to[i]][0] + ((w[i] & 1) ? w[i] - 1 : w[i]);
			int x = dp[to[i]][1] - dp[to[i]][0] + (w[i] & 1 ? 1 : -1);
			if(x > mx1) mx2 = mx1,mx1 = x;
			else if(x > mx2) mx2 = x;
		}
		else 
		{
			if(dp[to[i]][1] + 1 > mx1) mx2 = mx1,mx1 = dp[to[i]][1] + 1;
			else if(dp[to[i]][1] + 1 > mx2) mx2 = dp[to[i]][1] + 1;
		}
	}
	dp[x][1] = dp[x][0] + mx1; // 走出去一条边
	dp[x][2] = dp[x][0] + mx1 + mx2; // 走出去两条边
	for(int i = h[x];i;i = nxt[i])
	{
		if(to[i] == f) continue;
		if(w[i] > 1) dp[x][2] = max(dp[x][2],dp[to[i]][2] - dp[to[i]][0] + dp[x][0]);
	}
	ans = max(ans,dp[x][2]);
}

inline void solve()
{
	tot = ans = 0;
	memset(h,0,sizeof(h));
	n = read();
	for(int i = 1,u,v,c;i < n;i ++)
	{
		u = read();
		v = read();
		c = read();
		add(u,v,c);
		add(v,u,c);
	}
	dfs(1,0);
	write(ans);ent;
}

signed main()
{
	freopen("plan.in","r",stdin);freopen("plan.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	T = read();
	while(T --) solve();
	Blue_Archive;
}

T4:逃离冰场(skate)

不会,咕咕。

posted @ 2025-11-14 08:27  MyShiroko  阅读(26)  评论(1)    收藏  举报