2022.10.16———HZOI【CSP-S模拟19】游寄

Preface

排名 Rank 27/44

得分 100pts + 0pts + 4pts + 0pts = 104pts

总结:

T1 场切题我写了个shab贪心搞了 2h

T2 本来想小 dp 一把,然后发现 dp 假了

T3 考场思路是对的,但是不知道脑子哪里抽了就给否了。然后想到 smtwy 在超大定义域里随机撒点撒到 50pts 就来气,所以直接开始大力撒点。因为有 subtask 所以最后只有 4pts

T4 刚开始看到 40pts 的部分分挺开心,后来意识到这玩意的求方案数没那么简单。

T1:木棍,T2:环,T3:传令,T4:序列

T1 

思路跟别人不大一样。但是感觉是个假做法。

赛时的思路是 10 一共有五种分法,2+2+2+2+22+2+2+42+4+43+3+2+23+3+4,仔细思考了一下发现两个三个 2 能合成一个 6,两个 3 也能合成一个 624 也能合成一个 6,于是就把 10 拆成了 6+4。发现似乎是个方程,所以设了一下完全由 2 变成 6 的个数为 x 和由 24 变成 6 的个数为 y

n66 的个数,那么首先就是让 n3 全部转化为 6 (你留着他也没啥别的用啊)。

因为要尽量让 64 相等,那么有:

n6+x+y=n4y+n23xy2

移项整理得:

5(x+y)=2n42n6+n2x+y=2n42n6+n25

发现 x+y 即为新增的 6 的个数,正好是我们想要的,所以直接解出来赋值给 n6。因为方程满足了 n6=n4 (6 或者 4 多一个少一个可以忽略,因为你多一个 6 或者多一个 4 你又不能自己凑出来答案),所以此时 n6 就是能凑出来的 10 的个数。

发现这样做第三个样例是过不去的,于是怀着爆零的心态加了个nb特判,结果就 A 了。。。

具体加的特判就是如果 n4 极大的话就直接让 24 去全部合成 6,统计答案输出。n4 极大指的就是 n2 全部和 n4 去转换为 n6 后,n4 还是比 n6 大,即 n4n2n6+n2

T1
/*
	做总结
	T1 贪心+分类讨论?
	T2 找简单环。我    超
	T3 没想出来啥 有点像树的重心
	T4 魔鬼时空限制 还有看不出来是啥题 应该是个dp+组合数 以及样例似乎走丢了(
	
	开题顺序:T1 -> T2 -> T3 -> T4
	
	还有 T2 T4 要开文件
*/
#include <cstdio>
#include <cctype>
#include <iostream>
#define GMY (520&1314)
#define char_phi int
#define re register int
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout)
#define Endl cout << '\n'
#define _ ' '
#define Dl cerr << '\n'
#define DMARK cerr << "###"
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define ll __int128
using namespace std;
// inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }

/*
	考虑10的分法
	10 = 2+2+2+2+2
	   = 2+2+2+4
	   = 2+4+4
	   = 3+3+4
	   = 3+3+2+2
	于是就大力分类讨论?
	数据组数只有100是什么鬼啊(
	之前似乎在哪做过类似的题
	发现了神奇的东西
	可以把4给全部转成2
	哦吼
	但是会炸long long
	所以开 __int128 反正noip也让用
	于是便只剩两种情况了
	wow!!!
	然后再把n3给全部整成6
	那么剩下的就比较显然了,首先满足n3,再满足五个n2就行了
	
	c,假了
	我说出题人怎么会闲的没事考__int128
	但是经过一番思考我决定特判
	
	又想到了神奇的玩应。。。
	把2和3都转成6
	首先当然是把3全部转成6
	由于2+2 -> 4,2+4 -> 6
	所以考虑让6和4尽可能地等同需要分讨一下
	
	又假,wc
	
	我囸,两个小时了,我赶紧开别的题去
	唉希望别爆零
*/

inline ll read(){
	ll x = 0; char c;
	while (!isdigit(c = getchar()));
	do { x = (x << 3) + (x << 1) + (c & 15); } while (isdigit(c = getchar()));
	return x;
}
void ot(ll x){
	if (x > 9) ot(x/10);
	putchar((x%10)+48);
}

ll T, n2, n3, n4, final_ans, n6;

inline void work(){
	final_ans = 0;
	n2 = read(), n3 = read(), n4 = read();
	
	n6 = n3/2;
	
	if (n6 >= n4+n2/2){// n6已经够多了
		final_ans = (n4+n2/2);
	}
	else {// n6还少,需要转化
		// 然后考虑用2+4去转化还是用2+2+2去转化
		// 小解一把方程
		// 发现不用exgcd都
		
		if (n4-n2 > n6+n2)// 如果n4极大
			{ n6 = n6 + n2; final_ans = n6; goto OUT; }
		
		
		// cout << "res: "; ot((2*n4 - 2*n6 + n2) / 5), putchar('\n');
		
		ll res = (2*n4 - 2*n6 + n2) / 5;// x+y
		
		n6 = n6 + res;
		// res < 0 说明n6多,不可能,因为确定了 n6*2 < n4*2 + n2 了
		// 那么6的个数就是n6个啦。
		
		final_ans = n6;
	}
	
	OUT:{}
	
	ot(final_ans); putchar('\n');
}
#undef int
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a, a);
	#endif
	// Fastio_setup();
	T = read();
	while (T --)
		work();
	return GMY;
}

T2 

贺的陈嘉然先生的

T2
#include <iostream>
#include <algorithm>
#define GMY (520&1314)
#define char_phi signed
#define re register int
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define Endl cout << '\n'
#define _ ' '
#define Dl cerr << '\n'
#define DMARK cerr << "###"
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 5005
#define P 998244353
#define mod %
using namespace std;
inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }

/*
	
*/

long long n, final_ans;
long long a[N], f[N];

inline long long ksm(long long A, long long B){
	long long res(1);
	while (B != 0){
		if ((B & 1) == 1) res = res * A mod P;
		A = A * A mod P;
		B >>= 1;
	}
	return res;
}

inline void work(){
	cin >> n;
	for (re i = 1 ; i <= n ; ++ i)
		cin >> a[i];
	sort(a+1, a+n+1);
	
	f[0] = 1;
	for (re i = 1 ; i <= n ; ++ i){
		for (re j = a[i-1]+1 ; j <= a[i] ; ++ j)
			for (re k = j ; k >= 1 ; -- k)
				f[k] = (f[k] + f[k-1]) mod P;
		final_ans = (final_ans + (f[1]-a[i]+P) mod P) mod P;
		for (long long j = 0 ; j <= a[i] ; ++ j)
			f[j] = (f[j] + f[j+1] * (j+1) mod P * j mod P) mod P;
	}
	
	cout << final_ans * ksm(2, P-2) mod P << '\n';;
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a, a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

T3 

UPD

这个题是喜闻乐见的四倍经验题,Silver_ash 翻出来的(

P3942P2279P2016P3523

稍微改一下就过了。。。最后一道题似乎不是只改一下,于是我就懒得做了(

对此 Silver_ash 的评价如下:

// T3
// 弱化版 P3942 将军令
// 弱化弱化版 P2279 [HNOI2003]消防局的设立
// 弱的不是很化的改编版 P2016 战略游戏(准确的说这个是大胖守皇宫的弱化?)
// 加的不是很强的一样版 P3523 [POI2011] DYN-Dynamite
// 你谷全是重题, jbl


这回不是贺的了。从下午的两点多开始改(自己的nt思路),一直到晚上的七点,我tm改了一个下午。。。

先说思路。首先你二分答案一个时间。递归到叶子后往根回溯,然后贪心地选择当前点是否要作为国王选择的城市。

思路十分明确且简单,然后就是代码实现了。

然后代码实现我走了错路。(或者说我太弱了根本没调出来)

被覆盖指的是在某一作为国王选择的城市的点的影响范围内(就是你二分的时间内,距离就是影响范围)

我用结构体形式返回两个变量,分别是从当前点往下第一个没能被覆盖的点的深度(当然有可能因为贪心跑到他的上边,不过没关系),第二个是当前点往下第一个作为国王选择的城市的深度。然后就大力分类讨论,调了无数个数据点,最后忍痛放弃换了 SMTwy 的代码实现方式。

SMTwy 的实现方式特别简洁。当然我猜他的码风会让他的代码变得不是很简洁,不过我没看他代码。

设当前二分的值为 tmpans

整一个 a[] 数组,先考虑链上的情况。具体地:

  • 叶子节点的 a[] 为0。

  • 一个父亲的 a[] 值为其儿子 a[]+1(如果其儿子 a[]+1<tmpans)。

  • 当一个点的 a[]tmpans 时,将他的 a[] 值变为 tmpans-1

这么做的原因显然,是为了贪心嘛。当前点除了能往上覆盖 tmpans 长度之外,贪心地在他上面的 2×tmpans 处建立新的点。这样直接覆盖了更多的距离。自己画一条链就理解了。

但是毕竟链是链,不是树。考虑树的情况下应该咋合并。

假设一个节点 x,他的儿子传过来的 a[] 值中,最大值和最小值分别为 mxmn。首先a[x]肯定是要儿子于是做以下分类讨论:

  • 如果 mx<0 并且 mn<0,也就是说 x 的儿子把 x 给覆盖过了,那么根据贪心原则显然不会再选 x

  • 如果 mx+mn>0,也就是说 x 的儿子中覆盖了 x 的儿子不仅能把 x 给覆盖,还能覆盖掉 x 其他的儿子。那么此时就算 mxtmpans 也不会将 x 选上。

  • 其他情况下 xa[] 值应为 mx+1。原因也显然,为了让 x 的父亲知道最深的在哪。

还有最后根节点需要特判一下。因为你是是贪心地选 2×tmpans 的,有可能根节点正好处于tmpans2×tmpans 之间,你贪心的时候不会把根节点选上,但是你不选根节点你那一块就直接没被覆盖了。所以特判一下是否要选根节点。

代码实现较为简单。按照我那一版写的话代码实现较为恶心。

T3
#include <iostream>
#include <algorithm>
#define GMY (520&1314)
#define char_phi signed
#define re register int
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define Endl cout << '\n'
#define _ ' '
#define Dl cerr << '\n'
#define DMARK cerr << "###"
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 5005
#define P 998244353
#define mod %
using namespace std;
inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }

/*
	
*/

long long n, final_ans;
long long a[N], f[N];

inline long long ksm(long long A, long long B){
	long long res(1);
	while (B != 0){
		if ((B & 1) == 1) res = res * A mod P;
		A = A * A mod P;
		B >>= 1;
	}
	return res;
}

inline void work(){
	cin >> n;
	for (re i = 1 ; i <= n ; ++ i)
		cin >> a[i];
	sort(a+1, a+n+1);
	
	f[0] = 1;
	for (re i = 1 ; i <= n ; ++ i){
		for (re j = a[i-1]+1 ; j <= a[i] ; ++ j)
			for (re k = j ; k >= 1 ; -- k)
				f[k] = (f[k] + f[k-1]) mod P;
		final_ans = (final_ans + (f[1]-a[i]+P) mod P) mod P;
		for (long long j = 0 ; j <= a[i] ; ++ j)
			f[j] = (f[j] + f[j+1] * (j+1) mod P * j mod P) mod P;
	}
	
	cout << final_ans * ksm(2, P-2) mod P << '\n';;
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a, a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

作为纪念我还是挂一下我写的屎山代码。

屎山代码 (74pts)


#include <iostream>
#include <cstring>
#define GMY (520&1314)
#define char_phi signed
#define re register int
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define Endl cout << '\n'
#define _ ' '
#define Dl cerr << '\n'
#define DMARK cerr << "###"
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 200005
using namespace std;
inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }

// #define Debug

/*
	T3好简单好像
	我赛时想麻烦了
	我刚发现
	我赛时的想法似乎是正确的
	二分一个答案
	然后直接跑树形dp
	是O(nlogn)?
*/

/*
17 2
17 7
10 14
6 5
16 17
17 4
11 9
4 10
10 11
16 8
1 2
14 6
4 13
17 12
5 3
3 1
17 15
*/

/*
9 3
8 3
6 4
5 7
5 9
5 8
6 1
7 6
9 2
*/

/*
22 2
9 16
12 19
5 2
7 14
14 18
8 3
17 22
5 13
19 20
9 6
19 15
22 7
13 9
4 1
4 5
22 10
15 11
20 21
21 4
16 8
17 12
*/

/*
18 3
12 18
11 13
12 17
5 9
10 5
4 8
17 14
3 11
17 15
10 4
8 3
7 1
18 2
5 16
12 10
8 7
11 6
*/

/*
17 3
7 2
8 16
11 5
14 9
8 12
4 17
15 11
10 8
2 3
11 7
4 10
1 14
7 1
10 15
12 13
11 6
*/

int n, K, star_cnt, final_ans, chscnt, tmpans;
char chs[N];
int head[N], dep[N];

struct star {int v, nxt;};
struct RTN {int mxdep, mnchs;};

struct star e[N<<1];
struct RTN U_L_S;

inline void star_add(int u, int v){ e[++ star_cnt].v=v, e[star_cnt].nxt=head[u], head[u]=star_cnt; }

inline int Max(int x, int y){ return MAX(x, y); }
inline int Min(int x, int y){ return MIN(x, y); }

void getdep(int x, int faer){
	for (re i = head[x] ; i ; i = e[i].nxt){
		int v = e[i].v;
		if (v == faer)
			continue;
		dep[v] = dep[x]+1;
		getdep(v, x);
	}
}

RTN dfs(int x, int faer){
	int mxdep(-1145141919), mnchs(1145141919);
	for (re i = head[x] ; i ; i = e[i].nxt){
		int v = e[i].v;
		if (v == faer)
			continue;
		/*long long deper;
		deper = dfs(v, x);
		#ifdef Debug
		cerr << "感谢来自 " << v << " 老板的 " << deper << '\n';
		#endif*/
		RTN tmp = dfs(v, x);
		
		mxdep = Max(mxdep, tmp.mxdep);
		mnchs = Min(mnchs, tmp.mnchs);
	}
	
	#ifdef Debug
	cerr << "dfs: " << x << _ << dep[x] << _ << mxdep << _ << mnchs << '\n';
	Dl;
	#endif
	
	if (x == 1 and (mnchs-tmpans-1 >= dep[x] or mxdep-tmpans-1 >= dep[x]))
		{ chs[x] = true; return (RTN){1, 1}; }
	
	if (mxdep == -1145141919 and mnchs == 1145141919)// 啥都没干,是个叶子
		{ /*cerr << x << "[1]" << '\n'; Dl; Dl;*/ return (RTN){dep[x], mnchs}; }
	else if (mxdep-dep[x] >= tmpans and mnchs-dep[x]+mxdep-dep[x] > tmpans)// 该选
		{ /*cerr << x << "[2]" << '\n'; Dl; Dl;*/ chs[x] = true; return (RTN){dep[x]-tmpans-1, dep[x]}; }
	else if (mnchs-dep[x]+mxdep-dep[x] <= tmpans)// 当前点的mxdep被其他子树控制了,不用选,直接返回
		{ /*cerr << x << "[3]" << '\n'; Dl; Dl;*/ return (RTN){mnchs-tmpans-1, mnchs}; }
	else // 最最最普通的链
		{ /*cerr << x << "[4]" << '\n'; Dl; Dl;*/ return (RTN){mxdep, mnchs}; }
	
	/*if (mxdep == -1145141919)// 啥都没干,是个叶子
		{ cerr << x << "返回了[1]" << dep[x] << '\n'; return dep[x]; }
	if (mxdep-dep[x] >= tmpans)// 此处应当有chs
		{ cerr << x << "返回了[2]" << dep[x]-tmpans-1 << '\n'; chs[x] = true; return dep[x]-tmpans-1; }
	else // 不够格(
		{ cerr << x << "返回了[3] " << mxdep << '\n'; return mxdep; }*/
}
inline char check(int mid){// 那应当是check写挂了
	memset(chs, false, sizeof(chs)); chscnt = 0;
	
	#ifdef Debug
	cerr << "~~~~~~~~~~~~~mid: " << mid << '\n';
	#endif
	
	tmpans = mid;
	U_L_S = dfs(1, 0);
	
	for (re i = 1 ; i <= n ; ++ i)
		if (chs[i] == true)
			chscnt ++;
	
	#ifdef Debug
	
	cerr << "chscnt: " << chscnt << '\n';
	
	cerr << "选了:";
	for (re i = 1 ; i <= n ; ++ i)
		if (chs[i] == true)
			cerr << i << _;
	Dl;
	
	#endif
	
	if (chscnt <= K)
		return true;
	else 
		return false;
}

inline void work(){
	cin >> n >> K;
	for (re i = 1, uu, vv ; i <= n-1 ; ++ i)
		{ cin >> uu >> vv; star_add(uu, vv), star_add(vv, uu); }
	
	dep[1] = 1;
	getdep(1, 0);
	
	/*for (re i = 1 ; i <= n ; ++ i)
		if (check(i) == true)
			{final_ans = i; break;}*/
	#ifdef Debug
	Dl; Dl; Dl;
	#endif 
	
	int l, r, mid;
	l = 1, r = n;
	while (l <= r){
		mid = (l+r) >> 1;
		if (check(mid) == true)// 时限可以更小
			final_ans = mid, r = mid-1;
		else 
			l = mid+1;
		#ifdef Debug
		Dl; Dl; Dl;
		#endif
	}
	
	cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a, a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

T4 

没改(

posted @   char_phi  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示