首页 > 其他分享 >2022.10.16———HZOI【CSP-S模拟19】游寄

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

时间:2022-10-16 21:01:04浏览次数:80  
标签:10 17 16 19 text long HZOI tmpans define

\(\text{Preface}\)

排名 \(\text{Rank 27/44}\)

得分 \(\text{100pts + 0pts + 4pts + 0pts = 104pts}\)

总结:

\(\text{T1}\) 场切题我写了个shab贪心搞了 \(\text{2h}\)

\(\text{T2}\) 本来想小 \(\text{dp}\) 一把,然后发现 \(\text{dp}\) 假了

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

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

\(\mathfrak{T1}\ 木棍\)

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

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

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

因为要尽量让 \(6\) 和 \(4\) 相等,那么有:

\[n_6 + x + y = n_4 - y + \frac { n_2 - 3x - y } { 2 } \]

移项整理得:

\[\begin{aligned} 5(x+y) &= 2n_4 - 2n_6 + n_2\\ x + y &= \frac { 2n_4 - 2n_6 + n_2 }{ 5 } \end{aligned} \]

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

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

具体加的特判就是如果 \(n_4\) 极大的话就直接让 \(2\) 和 \(4\) 去全部合成 \(6\),统计答案输出。\(n_4\) 极大指的就是 \(n_2\) 全部和 \(n_4\) 去转换为 \(n_6\) 后,\(n_4\) 还是比 \(n_6\) 大,即 \(n_4 - n_2 >= n_6 + n_2\)。

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;
}

\(\mathfrak{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;
}

\(\mathfrak{T3}\ 传令\)

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

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

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

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

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

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

\(\text{SMTwy}\) 的实现方式特别简洁。当然我猜他的习惯会让他的代码变得不是很简洁,不过我没看他代码。

设当前二分的值为 tmpans

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

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

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

  • 当一个点的 a[] 值 \(\ge \text{tmpans}\) 时,将他的 a[] 值变为 \(\text{tmpans-1}\)。

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

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

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

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

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

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

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

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

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;
}

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

屎山代码 $\text{(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;
}

\(\mathfrak{T4}\ 序列\)

没改(

标签:10,17,16,19,text,long,HZOI,tmpans,define
From: https://www.cnblogs.com/charphi/p/16796932.html

相关文章

  • csp-s模拟19[木棍,环,传令,序列]
    csp-s模拟19[木棍,环,传令,序列]木棍就是个分讨,注意先\(3,4\)配就行here#include<bits/stdc++.h>#defineLLlonglong#defineReregisterint#defineLDdo......
  • 10.16
    #include<stdio.h>#include<math.h>intmain(){ inta,n; scanf("%d%d",&a,&n); inti,sum=0;  for(i=2;i<=n;i++) { a=a/pow(10,i-2)+a*10; sum=a+sum; }......
  • CSP-S模拟19
    这两天好累,不想改题T1木棍题意:有$a_1$个$2$,$a_2$个$3$,$a_3$个$4$,问最多能拼出多少个$10$题解:首先有这么几种方案$2$$3$$4$......
  • 2022-10-16 阿里云图标 全选 加入购物车代码
    varspan=document.querySelectorAll('.icon-cover');for(vari=0,len=span.length;i<len;i++){console.log(span[i].querySelector('span').click()......
  • 中国各省碳排放数据(1990-2021)
    中国各省碳排放数据(1990-2021)中国各省碳排放数据(1990-2021)中国各省碳排放数据(1990-2021)  最新版数据已整理为Excel格式,数据的时间区间为1990-2021年,内含“数据+计算......
  • 20221016笔记
    1.数据类型char//字符数据类型short//短整型int//整形long//长整型longlong//更长的整形float//单精度浮点数double//双精度浮点数#include<stdio.h>intmain(){pr......
  • CSP-S模拟19
    A.木棍发现一共就\((334)(3322)(442)(4222)(22222)\)几种情况,发现\(2\)通配,最后考虑他即可,先考虑\(334\)然后$3/4$必然只剩一种可以贡献,分别算一下,最后处理剩......
  • 10.16
    本周内容总结1.文件操作2.函数3.函数参数4.装饰器5.算法6.生成式7.内置函数8.可迭代对象9.迭代器对象1.文件操作1.文件的概念就是操作系统暴露给用户操作硬盘......
  • 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N
    【算法训练营day4】LeetCode24.两两交换链表中的结点LeetCode19.删除链表的倒数第N个结点LeetCode面试题02.07.链表相交LeetCode142.环形链表IILeetCode24.两两......
  • salt常用命令 | 16
    ***********模块***********查看模块列表modulesalt'minion'sys.list_modules查看指定module的function用法salt'minion'sys.list_functionsfile查看指定模块的详细用......