2022.10.20———HZOI【CSP-S模拟20】游寄

Preface

排名 Rank 31/43

得分 50pts + 20pts +20pts + 5pts = 95pts

T1 就我一个傻狗没切,我谔谔

T1 归隐,T2 按位或,T3 最短路径,T4 最短路

T1 

\ XIN 队算法 /\ 天下无敌 /

T1XIN 队』友情出题,可以发现a[i]=3a[i-1]-1,可以推式子也可以矩阵乘。

讲一下暴力。

别的我不知道,我赛时推出来个nb柿子

首先把 13 啥的都给转成 log3 的,然后根据对数运算公式相邻两个分身的乘积就是相邻两个分身的 log3 的加和。不过这个好像没啥用。

把每次新增的写出来,发现了神奇的事情:每次新增的数目是 3i2

于是答案表示为:

n+i=1n1i3ni+1

于是 50pts 暴力分就到手了

再往下就不会了,寄。

T1·50pts
#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 N 10000005
#define P 998244353
#define mod %
using namespace std;
inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }
inline int MIN(int x, int y){ return ((x < y) ? (x) : (y)); }
inline int MAX(int x, int y){ return ((x > y) ? (x) : (y)); }

/*
	\信队算法/\天下无敌/
	woc,规律来了
	首先全部变成log3的
	于是每次增加的就是3^(i-2)
	于是50pts到手,一趟递推过去即可
	考虑如何O(1)
	答案即为 n + (n-1)3^0 + (n-2)3^1 + ... 3^(n-2)
	写成sigma式
	n + Sigma_{i=1}^{n-1} {i * 3^(n-i-1)}
	嗯是这个柿子
	换句话说
	3^{n-1} + (3^{n-2}+...+3^0) + last
	所以说等比数列求和咋求和啊(
	而且这。。不大会啊。。
	悲伤qAq 止步于50pts
*/

long long n, final_ans;

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

void work(){
	cin >> n; final_ans = n;
	for (long long i = 1 ; i <= n-1 ; ++ i)
		final_ans = (final_ans + i * ksm(3, n-i-1) mod P) mod P;
	cout << final_ans << '\n';
}

#undef int
#define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(gy, gy);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

最后的答案是一个人类智慧结晶:

3n+2n14

T1·100pts
#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 P 998244353
#define mod %
using namespace std;
inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }
inline int MIN(int x, int y){ return ((x < y) ? (x) : (y)); }
inline int MAX(int x, int y){ return ((x > y) ? (x) : (y)); }

/*
	
*/

long long 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;
	cout << ((ksm(3, n) + 2 * n mod P) mod P - 1 + P) mod P * ksm(4, P-2) mod P << '\n';
}

#undef int
#define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(gy, gy);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

T2 

又是贺的陈嘉然的。

T2
#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 WT 85
#define P 998244353
#define mod %
using namespace std;
inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }
inline int MIN(int x, int y){ return ((x < y) ? (x) : (y)); }
inline int MAX(int x, int y){ return ((x > y) ? (x) : (y)); }

/*
	马八∑
*/

long long n, target, n1, n2, final_ans;

long long C[WT][WT], f[WT][WT];

inline void GetC(){
	C[0][0] = 1;
	for (re i = 1 ; i <= 80 ; ++ i){
		C[i][0] = 1;
		for (re j = 1 ; j <= i ; ++ j)
			C[i][j] = (C[i-1][j] + C[i-1][j-1]) mod P;
	}
}
inline void DP(){
	for (re i = 0 ; i <= n1 ; ++ i)
		for (re j = 0 ; j <= n2 ; ++ j)
			for (re I = 0 ; I <= i ; ++ I)
				for (re J = 0 ; J <= j ; ++ J)
					if ((I-J) % 3 == 0)
						f[i][j] += C[i][I] * C[j][J] mod P, f[i][j] -= ((f[i][j] >= P) ? (P) : (0));
}
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 >> target;
	
	GetC();
	
	for (re i = 0 ; i <= 60 ; ++ i)
		if ((target & ((long long)1<<i)) != 0)// 草 long long
			(((i & 1) == 1) ? (n1 ++) : (n2 ++));
	
	cerr << n1 << _ << n2 << '\n';
	
	DP();
	
	n %= (P-1);
	for (re i = n1 ; i >= 0 ; -- i)
		for (re j = n2 ; j >= 0 ; -- j)
			final_ans += (( (((n1-i+n2-j)&1) == 1) ? (-1) : (1) ) * C[n1][i] * C[n2][j] mod P * ksm(f[i][j], n) mod P + P) mod P, final_ans -= ((final_ans >= P) ? (P) : (0));
	
	cout << final_ans << '\n';
}

#undef int
#define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(or, or);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

T3 

没改 A,但是有 70pts。说一下怎么拿。

20pts 做法:

K=2 的部分分比较显然,直接 O(n2) 枚举两个点然后求一下他俩之间的路径长,所有的加起来乘个 Cm2 的逆元就行了。我考场拿的 20pts 就是这个。

50pts 做法:

暴力枚举 CmK 的所有方案,对于该方案中选出来的点建一棵生成树,然后求一个生成树的直径,对于直径上的边贡献只需要贡献一次,直径之外的边需要贡献两次。挺像昨天 T4 的。

思路很好想但是代码实现不咋简单。

70pts 做法:

lxhcr 说的一样,开始的时候对于每个关键点给他建成一颗虚树。还是暴力枚举 CmK 种方案,算贡献的时候因为少了很多点所以计算答案的效率较上面那个做法要高。没有实测但应该是这样。

70pts 按照 50pts 做法打的,加个数据淀粉质就 70pts 了(

T3·70pts
#include <iostream>
#include <cstring>
#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 N 2005
#define M 305
#define P 998244353
#define mod %
using namespace std;
inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }
inline int MIN(int x, int y){ return ((x < y) ? (x) : (y)); }
inline int MAX(int x, int y){ return ((x > y) ? (x) : (y)); }

/*
	sandom:对于选点建生成树,然后求一趟树的直径,树的直径只算一次贡献,不是树的直径的边给他计算两次贡献
*/

int n, m, K, liana, maxdep, star_cnt, lianb;
long long final_ans;
char tag[N];
int key[M], head[N], dep[N], pa[N], chs[M];
int ans[3] = {0, 104103145};
int fa[N][35];

struct star {int v, nxt;};

struct star e[N<<1];

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

void dfs1(int x, int faer){
	int k(0);
	for (; fa[x][k] != 0 ; ++ k)
		fa[x][k+1] = fa[fa[x][k]][k];
	pa[x] = k;
	
	for (re i = head[x] ; i ; i = e[i].nxt){
		int v = e[i].v;
		if (v == faer)
			continue;
		fa[v][0] = x; dep[v] = dep[x]+1;
		dfs1(v, x);
	}
}
inline int LCA(int x, int y){
	if (dep[x] < dep[y])
		swap(x, y);
	
	for (re k = pa[x] ; k >= 0 ; -- k)
		if (dep[fa[x][k]] >= dep[y])
			x = fa[x][k];
	
	if (x == y)
		return x;
	
	for (re k = pa[x] ; k >= 0 ; -- k)
		if (fa[x][k] != fa[y][k])
			x = fa[x][k], y = fa[y][k];
	
	return fa[x][0];
}
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 long long C(long long x, long long y){
	long long res(1);
	for (long long i = x ; i >= y+1 ; -- i)
		res = res * i mod P;
	for (long long i = (x-y) ; i >= 1 ; -- i)
		res = res * ksm(i, P-2) mod P;
	return res;
}

inline void MuseDash(int x, int lca){
	while (x != lca)
		tag[x] = true, x = fa[x][0];
	tag[lca] = true;
}
void dfs2(int x, int faer, int dep){
	if (dep > maxdep)
		maxdep = dep, liana = x;
	for (re i = head[x] ; i ; i = e[i].nxt){
		int v = e[i].v;
		if (v == faer or tag[v] == false)
			continue;
		dfs2(v, x, dep+1);
	}
}
void dfs3(int x, int faer, int dep){
	if (dep > maxdep)
		maxdep = dep, lianb = x;
	for (re i = head[x] ; i ; i = e[i].nxt){
		int v = e[i].v;
		if (v == faer or tag[v] == false)
			continue;
		dfs3(v, x, dep+1);
	}
}
void dfs4(int x, int faer){
	final_ans += 2;
	for (re i = head[x] ; i ; i = e[i].nxt){
		int v = e[i].v;
		if (v == faer or tag[v] == false)
			continue;
		dfs4(v, x);
	}
}

/*
huge:
- 收拾东西
- 身份证
- 拿手机
- 时间观念
*/

inline void calc(){
	// DMARK;
	
	/*cerr << "chs: ";
	for (re i = 1 ; i <= K ; ++ i)
		cerr << chs[i] << _;
	Dl;*/
	
	memset(tag, false, sizeof(tag));
	int lca = LCA(chs[1], chs[2]);
	MuseDash(chs[1], lca), MuseDash(chs[2], lca);
	
	for (re i = 3 ; i <= K ; ++ i)
		lca = LCA(lca, chs[i]), MuseDash(chs[i], lca);
	
	/*cerr << "tag: ";
	for (re i = 1 ; i <= n ; ++ i)
		cerr << (int)tag[i] << _;
	Dl;*/
	
	liana = lianb = maxdep = 0;
	
	dfs2(chs[1], 0, 1);
	maxdep = 0; dfs3(liana, 0, 1);
	
	// cerr << "Debug-直径: " << liana << _ << lianb << _ << maxdep << '\n';
	
	final_ans -= (maxdep-1);
	final_ans -= 2;
	
	dfs4(lianb, 0);
	
	// cerr << "ans: " << final_ans << '\n';
	
	// Dl; Dl; Dl; Dl; Dl;
	
	if (final_ans >= P)
		final_ans -= P;
}

void XIN_team(int x, int num){
	// cerr << "XIN队: " << x << _ << num << '\n';
	if (num == K)
		{calc(); return ;}
	if (x == m+1 or m-x+1 < K-num)// 上下界剪枝
		return ;
	// 选x
	chs[++ chs[0]] = key[x];
	XIN_team(x+1, num+1);
	chs[0] --;
	// 不选x
	XIN_team(x+1, num);
}

inline void work(){
	cin >> n >> m >> K;
	if (K == 3)
		goto TePan;
	for (re i = 1 ; i <= m ; ++ i)
		cin >> key[i];
	for (re i = 1, uu, vv ; i <= n-1 ; ++ i)
		{cin >> uu >> vv; star_add(uu, vv), star_add(vv, uu);}
	
	dep[1] = 1;
	dfs1(1, 0);
	
	/*for (re i = 1 ; i <= n ; ++ i)
		cerr << dep[i] << _;
	Dl;*/
	
	XIN_team(1, 0);
	// cerr << "分子: " << final_ans << '\n';
	// cerr << "分母: " << C(m, K) << '\n';
	cout << final_ans * ksm((C(m, K)), P-2) mod P << '\n';
	
	return ;
	
	TePan:{cout << ((m == 47) ? (ans[1]) : (0));}
}

#undef int
#define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(tree, tree);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

T4 

看到题目我高兴的很

看到题面我高兴的很

做法假了我难过的很


这题没改,叨一句 14pts 怎么拿

朴素的 winqizhi 算法就是直接按照幂次跑最短路。错误性显然。

考虑到第二档部分分开了 __int128 也拿不到,所以直接进行子任务分治,可以直接跑的就跑,不能的就跑 winqizhi 算法,最后多拿了4pts

T4·14pts
#include <iostream>
#include <ctime>
#include <cstring>
#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 N 100005
#define M 200005
#define P 1000000007
#define mod %
using namespace std;
inline void Fastio_setup(){ ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); }
inline int MIN(int x, int y){ return ((x < y) ? (x) : (y)); }
inline int MAX(int x, int y){ return ((x > y) ? (x) : (y)); }

/*
	woc,一眼丁真!
	这是明日方舟捏。
	还是少女前线捏。◀是叫干员吗(
	不是,这不就是最短路板子+记录路径吗?
	卡spfa?我就写spfa!
	但是我记得有卡随机化spfa的方法
	fuck u
	大样例秒挂
	哦我知道哪里挂了
	显然会挂
	~~人生苦短,我`用python~~
	要说这玩意肯定跟二进制有关
	两个相加可能进位也可能就是|一下,这个好判断
	关键在于你怎么记录
	开bitset?N个点开N个?
	flag:学线性基
	懒得打了,摆烂
	但是本着对winqizhi算法的崇拜决定之前的不删了,数据点分治即可
*/

int n, m, star_cnt, st, ed, L, R, mx;
long long final_ans;
char inq[N];
int head[N], q[M<<4], path[N];
long long dis[N];

struct star {int v, nxt; long long w;};

struct star e[M<<1];

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

inline void spfa(int x){
	memset(dis, 0x3f, sizeof(dis)); L = 0, R = -1;
	q[++ R] = x, inq[x] = true; dis[x] = 0;
	
	while (L <= R){
		x = q[L], L ++, inq[x] = false;
		for (re i = head[x] ; i ; i = e[i].nxt){
			int v = e[i].v;
			if (dis[v] > dis[x]+e[i].w){
				dis[v] = dis[x]+e[i].w;
				path[v] = x;
				if (inq[v] == false){
					if (L > 0 and (rand() & 1) == 1)
						q[-- L] = v;
					else 
						q[++ R] = v;
					inq[v] = true;
				}
			}
		}
	}
}

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;
}
void Print(int x){
	if (x == st)
		return ;
	Print(path[x]);// x从谁转移过来
	for (re i = head[path[x]] ; i ; i = e[i].nxt){
		if (e[i].v == x){
			final_ans = (final_ans + ksm(2, e[i].w)) mod P;
			break;
		}
	}
}

void work(){
	cin >> n >> m;
	for (re i = 1, uu, vv, ww ; i <= m ; ++ i)
		{cin >> uu >> vv >> ww; star_add(uu, vv, ww), star_add(vv, uu, ww); mx = MAX(mx, ww);}
	cin >> st >> ed;
	
	if (mx <= 40)
		goto Normal;
	
	spfa(st);
	
	
	if (dis[ed] == 0x3f3f3f3f3f3f3f3f)
		{cout << -1 << '\n'; return ;}
	
	Print(ed);
	
	cout << final_ans << '\n';
	
	return ;
	
	Normal:{
		// DMARK;
		for (re i = 1 ; i <= star_cnt ; ++ i)
			e[i].w = ksm(2, e[i].w);
		
		spfa(st);
		
		if (dis[ed] == 0x3f3f3f3f3f3f3f3f)
			{cout << -1 << '\n'; return ;}
		
		cout << dis[ed] << '\n';
	}
}

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