【考后】Accoders NOIP A层联测 32

行走(walk)

【题目背景】

\[「僕は歩くひとり 見上げた月は悲しみです」\\[0.5em] 「我独自行走着 抬头仰望那悲伤的月」\\[0.5em] 「僕は歩くひとり 淋しい人になりにけり」\\[0.5em] 「我独自行走着 终究成为孤戚一人」\\ \]

【题目描述】

小 M 喜欢四处行走。

一天夜晚,他来到了山顶,并眺望远方的公路。经过小 M 细致的观察,她一共能看见公路旁的 \(n\) 盏路灯。因为当天是节日,于是这些路灯一共可能发出 \(m\) 种不同的光。

细心的小 M 发现,每盏路灯都有自己不同的构造。每个时刻,每盏路灯所发出光的种类都可能会变化,并且第 \(i\) 盏路灯有一个长为 \(s_i\) 的变化序列,每过 \(s_i\) 个时刻,路灯的变化就会循环。

具体来说,在第 \(t\) 个时刻,第 \(i\) 盏路灯发出第 \(p_{i,(t-1 \bmod s_i) + 1}\) 种光。

因此,第 \(i\) 盏路灯在第 \(t, t + s_i, t + 2s_i, \ldots\) 个时刻发出的光种类是相同的,其中 \(t\) 为正整数。

小 M 发现,节日的灯光设计师很有品味。具体来讲,每盏路灯在一个循环内的每个时刻发出的光都是不同的,即对于每个序列 \(p_i\),序列中的元素两两不同

小 M 想要看到所有路灯都发出同一种颜色的光。已知小 M 会在第 \(l\) 到第 \(r\) 时刻观赏路灯,也就是说,她会在山顶停留 \(r − l + 1\) 个时刻。她想知道,有多少个时刻所有路灯都发出同一种颜色的光?

这个问题似乎对小 M 有些困难。她独自站在山顶,想了很久也没想明白。于是她想请您帮她算出满足条件的时刻数量。

【输入格式】

walk.in 中读入数据。

第一行四个正整数 \(n, m, l, r\)

接下来 \(n\) 行,第 \(i\) 行若干个正整数,第一个表示 \(s_i\),接下来 \(s_i\) 个正整数依次表示 \(p_{i,1}, p_{i,2}, \ldots , p_{i,s_i}\)

【输出格式】

输出到 walk.out 中。

输出一行一个非负整数,表示满足条件的时刻数量。

【样例 1 输入】

1 2 2 1 3
2 2 1 2
3 1 1

【样例 1 输出】

1 2

【样例 1 解释】

\(1\) 个时刻,两盏路灯发出的光种类分别为 \(1, 1\);第 \(2\) 个时刻,两盏路灯发出的光种类分别为 \(1, 2\);第 \(3\) 个时刻,两盏路灯发出的光种类分别为 \(1, 1\)

【样例 2 输入】

1 2 7 1 30
2 4 1 3 2 7
3 7 7 3 2 1 4 6 5

【样例 2 输出】

1 5

【样例 3】

见选手目录下的 walk/walk3.inwalk/walk3.ans

该样例满足测试点 \(3 ∼ 4\) 的限制。

【样例 4】

见选手目录下的 walk/walk4.inwalk/walk4.ans

【测试点约束】

对于所有测试点,\(2 ≤ n ≤ 10^5\)\(1 ≤ m ≤ 2 × 10^5\)\(1 ≤ s_i, ∑ si ≤ 2 × 10^5\)\(1 ≤ p_{i,j} ≤ m\)\(p_{i,a} \not= p_{i,b}(a \not= b)\)\(1 ≤ l ≤ r ≤ 10^{12}\)

\(t\) 表示最小的时刻,满足 \(t > 1\) 且第 \(t\) 个时刻所有路灯发出的光种类和第 \(1\) 个时刻相同。保证 \(t ≤ 10^{14}\)

【题解】

考虑到 \(m\) 不大,可以枚举灯的颜色。

如果一个颜色没有在某个灯出现,那不会对答案做贡献。

接下来钦定一个颜色 \(col\),设 \(a_i\)\(col\) 在灯 \(i\) 出现的时刻。

则对于所有合法的时间 \(x\),有方程:

\[\begin{cases} x \equiv a_1 \pmod {s_1}\\ x \equiv a_2 \pmod {s_2}\\ \vdots\\ x \equiv a_n \pmod {s_n} \end{cases} \]

裸的 扩展中国剩余定理 板子。

#include <iostream>
#include <vector>
typedef long long int llt;
#define pll std::pair<llt,llt>
#define vpl std::vector<std::pair<llt,llt>>
const int N = 200005;
int n, m;
llt l, r;
vpl buf[N];
int EXGCD(llt a,llt b,llt& x,llt& y) {
	if(!b) {
		x = 1;
		y = 0;
		return a;
	}
	int res = EXGCD(b,a%b,y,x);
	y = y-a/b*x;
	return res;
}
pll merge(llt a1,llt m1,llt a2,llt m2) {
	llt x, y;
	llt g = EXGCD(m1,m2,x,y);
	llt m = m1/g*m2;
	if(abs(a1-a2)%g) 
		return std :: make_pair(-1ll,-1ll);
	x = ((x*(a2-a1)/g)%(m2/g)+(m2/g))%(m2/g);
	return std :: make_pair(((a1+x*m1)%m+m)%m,m);
}
void EXCRT(vpl& func) {
	for(int i = 1;i < n;++i) {
		func[0] = merge(func[0].first,func[0].second,func[i].first,func[i].second);
		if(func[0].first < 0) 
			return;
	}
}
llt ans;
llt clac(llt x,pll& rec) {
	if(x < 0) return 0ll;
	return x/rec.second+(x%rec.second >= rec.first);
}
int main() {
	freopen("walk.in","r",stdin);
	freopen("walk.out","w",stdout);
	scanf("%d%d%lld%lld",&n,&m,&l,&r);
	for(int i = 1, s;i <= n;++i) {
		scanf("%d",&s);
		for(int j = 1, p;j <= s;++j) {
			scanf("%d",&p);
			buf[p].emplace_back(j%s,s);
		}
	}
	for(int i = 1;i <= m;++i) {
		if(buf[i].size() < n) 
			continue;
		EXCRT(buf[i]);
		if(buf[i][0].first < 0) 
			continue;
		ans += clac(r,buf[i][0])-clac(l-1,buf[i][0]);
	}
	printf("%lld\n",ans);
	return 0;
}

鸟之诗(air)

【题目背景】

\[\begin{aligned} 「&你的公主已经不在了,你必须离开,因为你拥有翅膀。」\\[0.5em] 「&对于我们这些没有翅膀的人类来说,天空是遥不可及的地方。所以,你要飞翔。\\[0.5em] &代替没有翅膀的我们,将人类的梦想和愿望,全都带回这片天空吧,拜托了!」\\[0.5em] &&——《AIR》 \end{aligned} \]

【题目描述】

为了完成家族的使命,你用力振翅飞翔。

具体的,你会振动 \(n\) 次翅膀,第 \(i\) 次的力度为一个正整数 \(f_i\)。由于你特殊的身体构造,所有 \(f_i\)最大公约数一定是 \(x\)。根据设定,你最后所处的高度是所有 \(f_i\)最小公倍数。你需要飞到高度为 \(y\) 的天空中。

由于你只剩下一只乌鸦的脑容量,已经记不清楚之前规划好的振翅方式,但是你清楚有许多种方案满足条件。你想知道,有多少种振翅的方式,即有多少个不同的长度为 \(n\) 的正整数序列 \(f\) 满足条件。

由于 \(x\)\(y\) 可能较大,你将会得到 \(x, y\) 的唯一分解。\(x\)\(y\) 可以分别用一个长度为 \(m\) 的非负整数序列 \(a, b\) 唯一表示。设 \(p_i\) 是第 \(i\) 个素数,那么

\[x = \prod\limits_{i = 1}^{m}p_i^{a_i} \]

\[y = \prod\limits_{i = 1}^{m}p_i^{b_i} \]

由于答案可能很大,于是你只需要求出答案对 \(998244353\) 取模后的结果就可以了。

【输入格式】

air.in 中读入数据。

第一行两个正整数 \(m,n\)

第二行 \(m\) 个非负整数 \(a_1, a_2, \ldots , a_n\)

第三行 \(m\) 个非负整数 \(b_1, b_2, \ldots , b_n\)

【输出格式】

输出到文件 air.out 中。

一行一个非负整数,表示答案对 \(998244353\) 取模后的结果。

【样例 1 输入】

1 2 3
2 0 1
3 0 2

【样例 1 输出】

1 6

【样例 2 输入】

1 2 5
2 1 1
3 2 2

【样例 2 输出】

1 900

【样例 3】

见选手目录下的 air/air3.inair/air3.ans

该样例满足测试点 \(2 ∼ 6\) 的限制。

【样例 4】

见选手目录下的 air/air4.inair/air4.ans

【测试点约束】

对于所有测试点,\(1 ≤ m ≤ 10^6\)\(1 ≤ n ≤ 10^{18}\)\(0 ≤ a_i < b_i < 998244353\)

【题解】

没有看过 AIR。

但是题挺水的。

考虑每一个质因子在每个 \(f\) 中的次数,减去没有最大次数或是没有最小次数的,再把同时没有最大/小次数的加回来。

#include <iostream>
//看题前盲猜了一波是《AIR》,还真是;
typedef long long int llt;
constexpr int mod = 998244353;
constexpr int N = 1000005;
int quick_pow(int _a,llt _n) {
	int _res = 1;
	while(_n) {
		if(_n&1) 
			_res = 1ll*_res*_a%mod;
		_a = 1ll*_a*_a%mod;
		_n >>= 1;
	}
	return _res;
}
llt n, ans = 1;
int m, p[N], q[N];
int main() {
	freopen("air.in","r",stdin);
	freopen("air.out","w",stdout);
	scanf("%d%lld",&m,&n);
	for(int i = 1;i <= m;++i) 
		scanf("%d",&p[i]);
	for(int i = 1;i <= m;++i) 
		scanf("%d",&q[i]);
	for(int i = 1;i <= m;++i) {
		if(p[i] == q[i]) 
			continue;
		ans = ans*(quick_pow(q[i]-p[i]+1,n)-(quick_pow(q[i]-p[i],n)<<1)+quick_pow(q[i]-p[i]-1,n))%mod;
	}
	ans = (ans%mod+mod)%mod;
	printf("%lld\n",ans);
	return 0;
}

核心共振(dimension)

【题目背景】

\[超越一切\ 震慑凡人\\ 带来终结\ 机械降神\\ 风暴之力\ 充满全身\\ 最后一击\ 核心共振 \]

【题目描述】

记在 \(m\) 维超空间中放置 \(n\)\(m − 1\) 维超平面,最多可以将该空间分割成 \(\operatorname{f} (n, m)\) 个区域。

\(\sum\limits_{i = 1}^{n}\operatorname{f}(i,m)\)

对一个神秘质数 \(p\) 取模。

【输入格式】

从文件 dimension.in 中读入数据。

一行三个正整数 \(n, m, p\)

【输出格式】

输出到文件 dimension.out 中。

一行一个整数,表示答案对 \(p\) 取模后的结果。

【样例 1 输入】

1 1 1 2

【样例 1 输出】

1 1

【样例 2 输入】

1 5 2 10007

【样例 2 输出】

1 41

【样例 3】

见选手目录下的 dimension/dimension3.indimension/dimension3.out。该样例满足测试点 \(6 ∼ 15\) 的限制。

【测试点约束】

对于所有测试点,\(0 ≤ n ≤ 10^{18}\)\(1 ≤ m ≤ 10^{18}\)\(2 ≤ p ≤ 2 × 10^7\)\(p\) 是质数。

【提示】

如果你对几何知识不太了解,你可以查阅选手目录下的 dimension/material.pdf

【题解】

根据讲解,我们得知:

\[\operatorname{f}(n,m) = \operatorname{f}(n-1,m)+\operatorname{f}(n-1,m-1) \]

可得:

\[\begin{aligned} \sum\limits_{i = 0}^{n}\operatorname{f}(i,m) &= \sum\limits_{i = 0}^{m}\sum\limits_{j = 0}^{n}\binom{j}{i}\\ &= \sum\limits_{i = 0}^{m}\binom{n+1}{i+1}\\ &= \sum\limits_{i = 0}^{m+1}\binom{n+1}{i}-1\\ &= \operatorname{f}(n+1,m+1)-1 \end{aligned} \]

\[\begin{aligned} \operatorname{f}(n,m) &\equiv \sum\limits_{i = 0}^{m} \binom{n}{i}\\ &\equiv \sum\limits_{i = 0}^{m} \binom{n \bmod p}{i \bmod p} \cdot \binom{\left\lfloor n / p \right\rfloor}{\left\lfloor i\, /\, p\right\rfloor}\\ &\equiv \sum\limits_{i = 0}^{\left\lfloor\frac{m}{p}\right\rfloor-1}\binom{\left\lfloor n / p\right\rfloor}{i} \times \sum\limits_{i = 0}^{p-1}\binom{n \bmod p}{i} + \binom{\left\lfloor n\;\! /\;\! p\right\rfloor}{\left\lfloor m / p\right\rfloor} \times \sum\limits_{i = 0}^{m \bmod p}\binom{n \bmod p}{i}\\ &\equiv \operatorname{f}\left(\left\lfloor\frac{n}{p}\right\rfloor,\left\lfloor\frac{m}{p}\right\rfloor-1\right) \times \sum\limits_{i = 0}^{p-1}\binom{n \bmod p}{i} + \binom{\left\lfloor n\;\! /\;\! p\right\rfloor}{\left\lfloor m / p\right\rfloor} \times \sum\limits_{i = 0}^{m \bmod p}\binom{n \bmod p}{i} \end{aligned} \]

可递归求解。

#include <iostream>
typedef long long int llt;
constexpr int N = 20000007;
llt n, m, p;
llt fact[N], inv[N];
llt quick_pow(llt base,llt exp) {
	llt res = 1;
	while(exp) {
		if(exp&1) 
			res = res*base%p;
		base = base*base%p;
		exp >>= 1;
	}
	return res;
}
llt C(llt n,llt m) {
	if(n < m) return 0ll;
	return 1ll*fact[n]*inv[m]%p*inv[n-m]%p;
}
llt Lucas(llt n,llt m) {
	if(n < m) return 0ll;
	if(m == 0) return 1ll;
	return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}
llt f(llt n,llt m) {
	if(n < m) 
		return quick_pow(2,n);
	if(m < 0) 
		return 0;
	if(n == 0) 
		return 1;
	llt cnt = Lucas(n/p,m/p);
	llt res = 0;
	for(int i = std :: min(n%p,m%p);i >= 0;--i) {
		res += C(n%p,i);
		if(res >= p) 
			res -= p;
	}
	return (res*cnt+quick_pow(2,n%p)*f(n/p,m/p-1))%p;
}
int main() {
	freopen("dimension.in","r",stdin);
	freopen("dimension.out","w",stdout);
	scanf("%lld%lld%lld",&n,&m,&p);
	fact[0] = inv[0] = 1;
	for(int i = 1;i < p;++i) 
		fact[i] = 1ll*fact[i-1]*i%p;
	inv[p-1] = quick_pow(fact[p-1],p-2);
	for(int i = p-2;i;--i) 
		inv[i] = inv[i+1]*(i+1ll)%p;
	printf("%lld\n",(f(n+1,m+1)-1+p)%p);
	return 0;
}

无双挑战(challenge)

【题目背景】

\[If\ you\ gonna\ hold\ me\ down\\[0.5em] And\ you’re\ not\ gonna\ let\ me\ in\\[0.5em] Into\ your\ castle\ walls\\[0.5em] None\ of\ you\ can\ keep\ them\\[0.5em] 如果想让我彷徨\ 说我不配这战场\\[0.5em] 在城堡外筑起高墙\ 最好再别无谓抵抗 \]

【题目描述】

小 M 是知名网络游戏《League of IOI AKers》(中文名为《IOI AKer 联盟》)的一名玩家。她所在的地区共有 \(n\) 座城市,通过 \(n − 1\) 条双向道路连接。对于任意两座城市,它们都可以互相到达。

现在,第 922 届 IOI AKer 联盟全球总决赛要开赛了。每座城市会派出一支队伍参赛。经过
小 M 细致的观察,第 \(i\) 座城市的能力值为一个 \(1\)\(m\) 之间的正整数 \(a_i\)。第 \(i\) 座城市派出的队伍的能力值和这座城市的能力值相等

对于一场城市 \(u\) 和城市 \(v\) 队伍之间的比赛,如果城市 \(u\) 队伍的能力值严格小于城市 \(v\) 队伍的能力值,并且城市 \(u\) 派出的队伍最终获胜,那么我们称城市 \(u\) 队伍完成了一次无双挑战。每一次无双挑战给观众带来的喜悦值 \(c\) 是一个正整数。如果城市 \(u\) 和城市 \(v\) 的距离,即城市 \(u\) 和城市 \(v\) 之间的路径长度为 \(l\),那么 \(c = (m − a_u) × l\)。但是,如果城市 \(u\) 的能力值不小于城市 \(v\) 的能力值,那么就算城市 \(u\) 派出的队伍最终获胜,也不会给观众带来任何喜悦值。

现在小 M 将会等概率随机加入一座城市的队伍,并在剩下的 \(n − 1\) 座城市派出的队伍中等概率随机挑选一支队伍作为对手。因为小 M 是这款游戏的 922 年老玩家,所以小 M一定会带领队伍获胜。现在,小 M 想让您告诉她,她期望能给观众带来的喜悦值是多少。

因为这个数可能不是整数,于是她只需要您告诉她这个数对 \(998244353\) 取模后的结果就可以了。

【输入格式】

第一行两个正整数 \(n, m\)

接下来一行 \(n\) 个正整数 \(a_1, a_2, \ldots , a_n\)

接下来 \(n − 1\) 行,每行两个正整数 \(u, v\),表示存在一条连接城市 \(u, v\) 的双向道路。

【输出格式】

输出一行一个非负整数,表示答案对 \(998244353\) 取模后的结果。

【样例 1 输入】

1 3 3
2 3 1 2
3 1 2
4 1 3

【样例 1 输出】

1 166374060

【样例 2 输入】

1 5 4
2 1 2 2 3 1
3 1 2
4 1 5
5 2 3
6 2 4

【样例 2 输出】

1 748683267

【样例 2 解释】

取模前的答案为 \(\frac{9}{4}\)

【样例 3】

见选手目录下的 challenge/challenge3.inchallenge/challenge3.out

该样例满足测试点 \(1 ∼ 4\) 的限制。

【样例 4】

见选手目录下的 challenge/challenge4.inchallenge/challenge4.out

该样例满足测试点 \(9 ∼ 12\) 的限制。

【样例 5】

见选手目录下的 challenge/challenge5.inchallenge/challenge5.out

【测试点约束】

对于所有测试点,\(2 ≤ n, m ≤ 8 × 10^5\)\(1 ≤ u \not= v ≤ n\)\(1 ≤ a_i ≤ m\),保任意两座城市都可以互相到达。

【题解】

点分治裸题。

#include <iostream>
constexpr int mod = 998244353;
constexpr int N = 800005;
int quick_pow(int base,int exp) {
	int res = 1;
	while(exp) {
		if(exp&1) 
			res = 1ll*res*base%mod;
		base = 1ll*base*base%mod;
		exp >>= 1;
	}
	return res;
}
long long ans;
int n, m;
struct EDGE {
	int t, next;
} edge[N<<1];
int head[N], edge_tot;
void add_edge(int f,int t) {
	edge[++edge_tot].next = head[f];
	edge[edge_tot].t = t;
	head[f] = edge_tot;
}
bool visit[N];
int root, node_tot;
int size[N], weight[N];
void find(int u,int p) {
	size[u] = 1;
	weight[u] = 0;
	for(int i = head[u];i;i = edge[i].next) {
		int v = edge[i].t;
		if(v == p||visit[v]) 
			continue;
		find(v,u);
		size[u] += size[v];
		if(size[v] > weight[u]) 
			weight[u] = size[v];
	}
	if(node_tot-size[u] > weight[u]) 
		weight[u] = node_tot-size[u];
	if(weight[u] < weight[root]) 
		root = u;
}
int val[N];
struct BIT {
	long long tree[N];
	void modify(int pos,long long val) {
		for(;pos <= m;pos += pos&-pos) {
			tree[pos] += val;
			if(tree[pos] >= mod) 
				tree[pos] -= mod;
			if(tree[pos] < 0) 
				tree[pos] += mod;
		}
	}
	long long query(int pos) {
		long long res = 0;
		for(;pos;pos -= pos&-pos) {
			res += tree[pos];
			if(res >= mod) 
				res -= mod;
		}
		return res;
	}
} t1, t2, t3, t4;
std :: pair<int,int> stk[N];
int top;
void get_dis(int u,int p,int dis) {
	stk[++top] = std :: make_pair(val[u],dis);
	for(int i = head[u];i;i = edge[i].next) {
		int v = edge[i].t;
		if(v == p||visit[v]) 
			continue;
		get_dis(v,u,dis+1);
	}
}
void solve(int u) {
	stk[top = 1] = std :: make_pair(val[u],0);
	t1.modify(val[u],m-val[u]);
	t4.modify(val[u],1);
	for(int i = head[u];i;i = edge[i].next) {
		int v = edge[i].t;
		if(visit[v]) 
			continue;
		int save = top;
		get_dis(v,u,1);
		for(int j = save+1;j <= top;++j) {
			ans = (ans+t1.query(stk[j].first-1)*stk[j].second+t2.query(stk[j].first-1))%mod;
			ans = (ans+(t3.query(m)-t3.query(stk[j].first)+(t4.query(m)-t4.query(stk[j].first))*stk[j].second)%mod*(m-stk[j].first)%mod+mod)%mod;
		}
		for(int j = save+1;j <= top;++j) {
			t1.modify(stk[j].first,m-stk[j].first);
			t2.modify(stk[j].first,1ll*(m-stk[j].first)*stk[j].second%mod);
			t3.modify(stk[j].first,stk[j].second);
			t4.modify(stk[j].first,1);
		}
	}
	for(int i = 1;i <= top;++i) {
		t1.modify(stk[i].first,stk[i].first-m);
		t2.modify(stk[i].first,1ll*(stk[i].first-m)*stk[i].second%mod);
		t3.modify(stk[i].first,mod-stk[i].second);
		t4.modify(stk[i].first,mod-1);
	}
}
void dfz(int u) {
	solve(u);
	visit[u] = true;
	for(int i = head[u];i;i = edge[i].next) {
		int v = edge[i].t;
		if(visit[v]) 
			continue;
		weight[root = 0] = node_tot = size[v];
		find(v,u);
		dfz(root);
	}
}
int main() {
	freopen("challenge.in","r",stdin);
	freopen("challenge.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;++i) 
		scanf("%d",&val[i]);
	for(int i = 1, u, v;i < n;++i) {
		scanf("%d%d",&u,&v);
		add_edge(u,v);
		add_edge(v,u);
	}
	weight[root = 0] = node_tot = n;
	find(1,0);
	dfz(root);
	ans = (ans%mod+mod)%mod;
	printf("%lld\n",1ll*ans*quick_pow(n,mod-2)%mod*quick_pow(n-1,mod-2)%mod);
	return 0;
}
posted @ 2022-11-21 16:23  bikuhiku  阅读(13)  评论(0编辑  收藏  举报