2.6 寒假训练营补题

ops/2025/2/11 2:00:26/

C Tokitsukaze and Balance String (hard)

题目描述

本题为《Tokitsukaze and Balance String (easy)》的困难版本,两题的唯一区别在于 n n n 的范围。

一个字符串是平衡的,当且仅当字符串中 "01" 连续子串的个数与 "10" 连续子串的个数相同。

定义字符串 s s s v a l ( s ) val(s) val(s) 为这样的位置数量:

  • 若当前位置上的字符为 '0',将其反置后成为 '1',此时字符串 s s s 是平衡的;
  • 若当前位置上的字符为 '1',将其反置后成为 '0',此时字符串 s s s 是平衡的。

现在 Tokitsukaze 有一个长度为 n n n,仅由字符 '0''1''?' 构成的字符串 s s s

其中,'?' 可以替换成 '0' 或者 '1'。假设 '?' 的个数为 p p p,显然将每个 '?' 都替换后,总共可以得到 2 p 2^p 2p 个不同的 s s s,Tokitsukaze 想知道所有 2 p 2^p 2p 个不同的 s s s 对应的 v a l ( s ) val(s) val(s) 之和是多少。由于答案可能很大,请将答案对 ( 1 0 9 + 7 ) (10^9 + 7) (109+7) 取模后输出。

子串为从原字符串中,连续的选择一段字符(可以全选、可以不选)得到的新字符串。

输入描述

每个测试文件均包含多组测试数据。第一行输入一个整数 T ( 1 ≤ T ≤ 2 × 1 0 5 ) T(1\leq T\leq 2\times 10^5) T(1T2×105) 代表数据组数,每组测试数据描述如下:

  • 第一行输入一个整数 n ( 1 ≤ n ≤ 2 × 1 0 5 ) n(1\leq n\leq 2\times 10^5) n(1n2×105) 代表字符串长度。
  • 第二行输入一个长度为 n n n、仅由 '0''1''?' 构成的字符串 s s s

除此之外,保证单个测试文件的 n n n 之和不超过 2 × 1 0 5 2\times 10^5 2×105

输出描述

对于每一组测试数据,新起一行。输出一个整数,代表全部 2 p 2^p 2p 个不同的 s s s 对应的 v a l ( s ) val(s) val(s) 之和。由于答案可能很大,请将答案对 ( 1 0 9 + 7 ) (10^9 + 7) (109+7) 取模后输出。

示例

输入

5
1
0
4
??01
5
?????
10
010??1101?
50
??1??0?0???????0?1??00?1???1??0?11??1011001???00??

输出

1
8
80
40
421772709

说明

  • 对于第一组测试数据,反置字符串的第一个字符,得到字符串 "1",此时,"01" 子串与 "10" 子串个数均为 0 0 0,平衡。由于在这个样例中,只有一种不同的 s s s,所以答案即为 v a l ( " 1 " ) = 1 val("1") = 1 val("1")=1
  • 对于第二组测试数据,通过替换 '?' 得到 4 4 4 种不同的 s s s,分别为:"0001""0101""1001""1101"。限制于篇幅,我们在此仅详细展开讨论 "0001" 的情况。
    • 翻转第一个字符,得到 "1001",此时,"01" 子串与 "10" 子串个数均为 1 1 1,平衡。
    • 翻转第二个字符,得到 "0101",此时,"01" 子串个数为 2 2 2"10" 子串个数为 1 1 1,不平衡。
    • 翻转第三个字符,得到 "0011",此时,"01" 子串个数为 1 1 1"10" 子串个数为 0 0 0,不平衡。
    • 翻转第四个字符,得到 "0000",此时,"01" 子串与 "10" 子串个数均为 0 0 0,平衡。
      综上,得到 v a l ( " 0001 " ) = 2 val("0001") = 2 val("0001")=2。同理可得其他三个字符串。最终答案为 2 + 2 + 2 + 2 = 8 2 + 2 + 2 + 2 = 8 2+2+2+2=8

解题思路

核心性质

对于长度为 n n n 的 01 字符串 s s s,当 s 1 s_1 s1 s n s_n sn 相等时,“01” 与 “10” 子串数量相等。所以在 2 ≤ i ≤ n − 1 2\leq i\leq n - 1 2in1 范围内的 ? 可以随意填充,不会影响 “01” 与 “10” 子串的数量。

定义变量

2 ≤ i ≤ n − 1 2\leq i\leq n - 1 2in1 中的 ? 个数为 c n t cnt cnt

不考虑 s 1 s_1 s1 s n s_n sn? 的情况

情况一: s 1 = s n s_1 = s_n s1=sn

s 1 s_1 s1 等于 s n s_n sn 时, 2 ≤ i ≤ n − 1 2\leq i\leq n - 1 2in1 中的 s i s_i si 可以随意翻转。此时 v a l ( s ) = n − 2 val(s)=n - 2 val(s)=n2,那么这部分对结果的贡献为 2 c n t ⋅ ( n − 2 ) 2^{cnt}\cdot(n - 2) 2cnt(n2)

情况二: s 1 ≠ s n s_1 \neq s_n s1=sn

s 1 s_1 s1 不等于 s n s_n sn 时,必须翻转 s 1 s_1 s1 或者 s n s_n sn 才能使字符串满足条件,即 v a l ( s ) = 2 val(s)=2 val(s)=2,这部分对结果的贡献为 2 c n t ⋅ 2 2^{cnt}\cdot2 2cnt2

考虑 s 1 s_1 s1 s n s_n sn? 的情况

s 1 s_1 s1 s n s_n sn? 时,需要再进行分类讨论,具体细节可参考后续代码实现。

优化点

由于 c n t cnt cnt 最多等于 n − 2 n - 2 n2,我们可以对 2 2 2 的幂进行预处理,这样就不需要使用快速幂算法,能将时间复杂度控制在 O ( n ) O(n) O(n)

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod= 1e9+7;
int qpow(int a,int b)
{int res=1;while(b){if(b&1)res=res*a%mod;a=a*a%mod;b/=2;}return res;
}
void solve()
{int n;cin>>n;string s;cin>>s;s=" "+s;if(n==1){if(s[1]!='?')cout<<1<<'\n';else cout<<2<<'\n';}else{int cnt=0;for(int i=2;i<=n-1;i++)if(s[i]=='?')cnt++;int ans=qpow(2,cnt);if(s[1]==s[n]){if(s[1]!='?')ans=ans*(n-2)%mod;else ans=ans*2*n%mod;}else{if(s[1]=='?' && s[n]!='?')ans=ans*n%mod;else if(s[1]!='?' && s[n]=='?')ans=ans*n%mod;else ans=ans*2%mod;}cout<<ans<<'\n';}
}signed main()
{  int t;cin>>t;while(t--)solve();return 0;
}

A Tokitsukaze and Absolute Expectation

题目描述

Tokitsukaze 有一个由 n n n 个整数组成的序列 { a 1 , a 2 , … , a n } \{a_1, a_2, \ldots, a_n\} {a1,a2,,an},其中第 i i i 个元素 a i a_i ai 的值在区间 [ l i , r i ] [l_i, r_i] [li,ri] 中独立地、等概率随机生成。

定义一个序列的价值为 v a l ( a ) = ∑ i = 2 n ∣ a i − 1 − a i ∣ val(a)=\sum_{i = 2}^{n}|a_{i - 1}-a_i| val(a)=i=2nai1ai,Tokitsukaze 想知道 v a l ( a ) val(a) val(a) 的期望。

输入描述

每个测试文件均包含多组测试数据。第一行输入一个整数 T ( 1 ≤ T ≤ 1 0 5 ) T(1\leq T\leq 10^5) T(1T105) 代表数据组数,每组测试数据描述如下:

  • 第一行输入一个整数 n ( 2 ≤ n ≤ 2 × 1 0 5 ) n(2\leq n\leq 2\times 10^5) n(2n2×105) 代表序列中元素的数量。
  • 此后 n n n 行,第 i i i 行输入两个整数 l i , r i ( 1 ≤ l i ≤ r i ≤ 1 0 9 ) l_i, r_i(1\leq l_i\leq r_i\leq 10^9) li,ri(1liri109) 代表第 i i i 个元素的取值范围。

除此之外,保证单个测试文件的 n n n 之和不超过 2 × 1 0 5 2\times 10^5 2×105

输出描述

可以证明答案可以表示为一个不可约分数 p q \frac{p}{q} qp,为了避免精度问题,请直接输出整数 ( p ⋅ q − 1 m o d M ) (p\cdot q^{-1}\bmod M) (pq1modM) 作为答案,其中 M = 1 0 9 + 7 M = 10^9 + 7 M=109+7 q − 1 q^{-1} q1 是满足 q × q − 1 ≡ 1 ( m o d M ) q\times q^{-1}\equiv 1(\bmod M) q×q11(modM) 的整数。

更具体地,你需要找到一个整数 x ∈ [ 0 , 1 0 9 + 7 ) x\in[0, 10^9 + 7) x[0,109+7) 满足 x × q x\times q x×q 1 0 9 + 7 10^9 + 7 109+7 取模等于 p p p,您可以查看样例解释得到更具体的说明。

示例

输入

2
3
1 2
1 2
1 3
4
4 8
2 3
4 10
4 7

输出

333333337
214285726

说明

对于第一组测试数据,总共有 12 12 12 种序列,每种序列出现的概率均相等,如下:

  • v a l ( { 1 , 1 , 1 } ) = ∣ 1 − 1 ∣ + ∣ 1 − 1 ∣ = 0 val(\{1, 1, 1\}) = |1 - 1|+|1 - 1| = 0 val({1,1,1})=∣11∣+∣11∣=0
  • v a l ( { 1 , 1 , 2 } ) = ∣ 1 − 1 ∣ + ∣ 1 − 2 ∣ = 1 val(\{1, 1, 2\}) = |1 - 1|+|1 - 2| = 1 val({1,1,2})=∣11∣+∣12∣=1
  • v a l ( { 1 , 1 , 3 } ) = ∣ 1 − 1 ∣ + ∣ 1 − 3 ∣ = 2 val(\{1, 1, 3\}) = |1 - 1|+|1 - 3| = 2 val({1,1,3})=∣11∣+∣13∣=2
  • v a l ( { 1 , 2 , 1 } ) = ∣ 1 − 2 ∣ + ∣ 2 − 1 ∣ = 2 val(\{1, 2, 1\}) = |1 - 2|+|2 - 1| = 2 val({1,2,1})=∣12∣+∣21∣=2
  • v a l ( { 1 , 2 , 2 } ) = ∣ 1 − 2 ∣ + ∣ 2 − 2 ∣ = 1 val(\{1, 2, 2\}) = |1 - 2|+|2 - 2| = 1 val({1,2,2})=∣12∣+∣22∣=1
  • v a l ( { 1 , 2 , 3 } ) = ∣ 1 − 2 ∣ + ∣ 2 − 3 ∣ = 2 val(\{1, 2, 3\}) = |1 - 2|+|2 - 3| = 2 val({1,2,3})=∣12∣+∣23∣=2
  • v a l ( { 2 , 1 , 1 } ) = ∣ 2 − 1 ∣ + ∣ 1 − 1 ∣ = 1 val(\{2, 1, 1\}) = |2 - 1|+|1 - 1| = 1 val({2,1,1})=∣21∣+∣11∣=1
  • v a l ( { 2 , 1 , 2 } ) = ∣ 2 − 1 ∣ + ∣ 1 − 2 ∣ = 2 val(\{2, 1, 2\}) = |2 - 1|+|1 - 2| = 2 val({2,1,2})=∣21∣+∣12∣=2
  • v a l ( { 2 , 1 , 3 } ) = ∣ 2 − 1 ∣ + ∣ 1 − 3 ∣ = 3 val(\{2, 1, 3\}) = |2 - 1|+|1 - 3| = 3 val({2,1,3})=∣21∣+∣13∣=3
  • v a l ( { 2 , 2 , 1 } ) = ∣ 2 − 2 ∣ + ∣ 2 − 1 ∣ = 1 val(\{2, 2, 1\}) = |2 - 2|+|2 - 1| = 1 val({2,2,1})=∣22∣+∣21∣=1
  • v a l ( { 2 , 2 , 2 } ) = ∣ 2 − 2 ∣ + ∣ 2 − 2 ∣ = 0 val(\{2, 2, 2\}) = |2 - 2|+|2 - 2| = 0 val({2,2,2})=∣22∣+∣22∣=0
  • v a l ( { 2 , 2 , 3 } ) = ∣ 2 − 2 ∣ + ∣ 2 − 3 ∣ = 1 val(\{2, 2, 3\}) = |2 - 2|+|2 - 3| = 1 val({2,2,3})=∣22∣+∣23∣=1

综上所述,期望值为 0 + 1 + 2 + 2 + 1 + 2 + 1 + 2 + 3 + 1 + 0 + 1 12 = 4 3 \frac{0 + 1+2 + 2+1 + 2+1 + 2+3 + 1+0 + 1}{12}=\frac{4}{3} 120+1+2+2+1+2+1+2+3+1+0+1=34。我们能够找到, 333333337 × 3 = 1000000011 333333337\times 3 = 1000000011 333333337×3=1000000011,对 1 0 9 + 7 10^9 + 7 109+7 取模后恰好等于分子 4 4 4,所以 333333337 333333337 333333337 是需要输出的答案。

解题思路

链接:https://ac.nowcoder.com/discuss/1454104
来源:牛客网

核心转化

根据期望的线性性质,可以转化成求 ∣ a i − a i − 1 ∣ |a_i - a_{i - 1}| aiai1 的期望之和。那么问题就转化成了 ∣ a i − a i − 1 ∣ |a_i - a_{i - 1}| aiai1 的期望。

分母计算

由于 a i − 1 a_{i - 1} ai1 a i a_i ai 在区间 [ l i − 1 , r i − 1 ] [l_{i - 1}, r_{i - 1}] [li1,ri1] [ l i , r i ] [l_i, r_i] [li,ri] 等概率随机,所以分母为 ( r i − 1 − l i − 1 + 1 ) ⋅ ( r i − l i + 1 ) (r_{i - 1}-l_{i - 1}+1)\cdot(r_i - l_i + 1) (ri1li1+1)(rili+1)

分子计算

分子是 a i − 1 a_{i - 1} ai1 a i a_i ai 绝对值之差的所有情况之和。假设目前计算的是 [ l 1 , r 1 ] [l_1, r_1] [l1,r1] [ l 2 , r 2 ] [l_2, r_2] [l2,r2]。设 [ x , y ] [x, y] [x,y] 为这两个区间的交,即 x = max ⁡ ( l 1 , l 2 ) x = \max(l_1, l_2) x=max(l1,l2) y = min ⁡ ( r 1 , r 2 ) y=\min(r_1, r_2) y=min(r1,r2)。然后通过下面 3 个部分进行计算:

  1. [ l 1 , x − 1 ] [l_1, x - 1] [l1,x1] [ l 2 , r 2 ] [l_2, r_2] [l2,r2]
  2. [ x , y ] [x, y] [x,y] [ y + 1 , r 2 ] [y + 1, r_2] [y+1,r2]
  3. [ x , y ] [x, y] [x,y] [ x , y ] [x, y] [x,y]

情况 1 和情况 2 很好算,因为它们区间都没有交。实现可以参考代码中的 cal2 函数。

情况 3 因为它是对称的,可以推出一个式子。式子可以参考代码中的 cal3 函数。

复杂度分析

求完分子就做完了。由于每次需要求一下分母的逆元,所以时间复杂度为 O ( n log ⁡ m ) O(n\log m) O(nlogm) m = 1 0 9 + 7 m = 10^9 + 7 m=109+7

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=5e5+10;
const int mod=1e9+7;
ll qpow(ll a,ll b)
{ll res=1;while(b>0){if(b&1) res=res*a%mod;a=a*a%mod;b>>=1;}return res;
}
ll inv(ll x){return qpow(x,mod-2);}
const ll inv3=inv(3);
ll cal3(int l,int r)
{int n=r-l+1;return 1LL*(n-1)*n%mod*(n+1)%mod*inv3%mod;
}
ll cal2(int l1,int r1,int l2,int r2)
{if(l1>r1||l2>r2) return 0;ll res=0;res+=1LL*(l2+r2)*(r2-l2+1)/2%mod*(r1-l1+1);res-=1LL*(l1+r1)*(r1-l1+1)/2%mod*(r2-l2+1);res%=mod;if(res<0) return res+mod;return res;
}
ll cal(int l1,int r1,int l2,int r2)
{if(l1>l2){swap(l1,l2);swap(r1,r2);}int x,y;x=max(l1,l2);y=min(r1,r2);if(x>y) return cal2(l1,r1,l2,r2);ll res=0;res+=cal2(l1,x-1,l2,r2);res+=cal2(x,y,y+1,max(r1,r2));res+=cal3(x,y);return res%mod;
}
int l[MAX],r[MAX];
signed main()
{int t,n,i;ll ans,fz,fm;scanf("%d",&t);while(t--){scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d%d",&l[i],&r[i]);ans=0;for(i=2;i<=n;i++){fz=cal(l[i-1],r[i-1],l[i],r[i]);fm=1LL*(r[i-1]-l[i-1]+1)*(r[i]-l[i]+1)%mod;ans=(ans+fz*inv(fm))%mod;}printf("%lld\n",ans);}return 0;
}

F Tokitsukaze and Kth Problem (easy)

题目描述

本题与《Tokitsukaze and Kth Problem (hard)》共享题目背景,可以视作困难版本的子问题。若能通过 hard,在做简单修改后,必能通过 easy。

Tokitsukaze 有一个由 n n n 个整数组成的序列 { a 1 , a 2 , … , a n } \{a_1, a_2, \ldots, a_n\} {a1,a2,,an}。他定义一个二元组 ( i , j ) (i, j) (i,j) 满足 1 ≤ i < j ≤ n 1\leq i < j\leq n 1i<jn,并定义这个二元组对应的值 f ( i , j ) = ( a i + a j ) m o d p f(i,j)=(a_i + a_j)\bmod p f(i,j)=(ai+aj)modp

他想知道,对于全部不同的二元组 ( i , j ) (i, j) (i,j),全部值 f ( i , j ) f(i,j) f(i,j) 的前 k k k 大值分别为多少。如果不存在,则输出 − 1 -1 1 替代。

输入描述

每个测试文件均包含多组测试数据。第一行输入一个整数 T ( 1 ≤ T ≤ 1 0 5 ) T(1\leq T\leq 10^5) T(1T105) 代表数据组数,每组测试数据描述如下:

  • 第一行输入三个整数 n , p , k ( 2 ≤ n ≤ 2 × 1 0 5 ; 1 ≤ p ≤ 1 0 9 ; 1 ≤ k ≤ 2 × 1 0 5 ) n, p, k(2\leq n\leq 2\times 10^5; 1\leq p\leq 10^9; 1\leq k\leq 2\times 10^5) n,p,k(2n2×105;1p109;1k2×105) 代表序列中的元素数量、模数、询问大小。
  • 第二行输入 n n n 个整数 a 1 , a 2 , … , a n ( 0 ≤ a i ≤ 1 0 9 ) a_1, a_2, \ldots, a_n(0\leq a_i\leq 10^9) a1,a2,,an(0ai109) 代表序列中的元素。

除此之外,保证单个测试文件的 n n n 之和不超过 2 × 1 0 5 2\times 10^5 2×105 k k k 之和不超过 2 × 1 0 5 2\times 10^5 2×105

输出描述

对于每一组测试数据,新起一行。连续输出 k k k 个整数,第 x x x 个整数表示 f ( i , j ) f(i,j) f(i,j) 的第 x x x 大值,如果不存在第 x x x 大值,输出 − 1 -1 1 替代。

示例

输入

3
3 10 8
2 4 8
4 6 4
1 2 3 3
5 10 10
1 2 3 4 5

输出

6 2 0 -1 -1 -1 -1 -1
5 5 4 4
9 8 7 7 6 6 5 5 4 3

说明

对于第二组测试数据,一共有六个不同的二元组,对应的值分别为:

  • f ( 1 , 2 ) = ( 1 + 2 ) m o d 6 = 3 f(1,2)=(1 + 2)\bmod 6 = 3 f(1,2)=(1+2)mod6=3
  • f ( 1 , 3 ) = ( 1 + 3 ) m o d 6 = 4 f(1,3)=(1 + 3)\bmod 6 = 4 f(1,3)=(1+3)mod6=4
  • f ( 1 , 4 ) = ( 1 + 3 ) m o d 6 = 4 f(1,4)=(1 + 3)\bmod 6 = 4 f(1,4)=(1+3)mod6=4
  • f ( 2 , 3 ) = ( 2 + 3 ) m o d 6 = 5 f(2,3)=(2 + 3)\bmod 6 = 5 f(2,3)=(2+3)mod6=5
  • f ( 2 , 4 ) = ( 2 + 3 ) m o d 6 = 5 f(2,4)=(2 + 3)\bmod 6 = 5 f(2,4)=(2+3)mod6=5
  • f ( 3 , 4 ) = ( 3 + 3 ) m o d 6 = 0 f(3,4)=(3 + 3)\bmod 6 = 0 f(3,4)=(3+3)mod6=0

排序后得到 { 0 , 3 , 4 , 4 , 5 , 5 } \{0, 3, 4, 4, 5, 5\} {0,3,4,4,5,5}

解题思路

Solution 1:二分答案

这类求第 k k k 大,或者前 k k k 大类的题,一般可以先考虑二分答案。

  • 由于 easy 版本与序列顺序无关,所以可以先对序列进行排序(sort),然后二分答案后用双指针数一下有多少对大于等于答案。
  • 求出第 k k k 大后,大于答案的对可以暴力求出来,剩下的再用答案填。

时间复杂度 O ( n log ⁡ V + k ) O(n\log V + k) O(nlogV+k),其中 V V V 为值域。

代码链接:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=75401127

Solution 2:堆

我们可以构造一种方案,使得堆内必定存在当前的最大值。这样只要从堆中弹出 k k k 次就是前 k k k 大。

  • 对于这道题,可以枚举 a i a_i ai,对于每个 a i a_i ai,找到与它匹配能使 f ( i , j ) f(i,j) f(i,j) 最大的 a j a_j aj 放入堆中。
  • 每次从堆中弹出一个东西,我们就把下一个与 a i a_i ai 匹配的 a j a_j aj 放入堆中(如果有的话)。

时间复杂度 O ( ( n + k ) log ⁡ n ) O((n + k)\log n) O((n+k)logn)

代码链接:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=75401133

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1000010, mod = 1e9 + 7;
#define int long long 
int a[N], b[N];
int n, m, k;
void solve() {int p;cin >> n >> p >> k;for (int i = 1; i <= n; i++) {cin >> a[i];a[i] %= p;}sort(a + 1, a + 1 + n);auto work = [&](int x) -> long long {int ans = 0;for (int i = 1, j = n; i <= n; i++) {while (j >= 1 && a[i] + a[j] >= x) j--;if (j > i)  ans += n - j;else ans += n - i;}return ans;};auto check = [&](int x) -> long long {return work(x) + work(p + x) - work(p);};int l = 0, r = p - 1;while (l <= r) {int mid = l + r >> 1;if (check(mid) >= k)  l = mid + 1;else r = mid - 1;}vector<int> ans;for (int i = 1, j = n, c = n; i <= n; i++) {while (j >= 1 && a[i] + a[j] >= l) j--;while (c >= 1 && a[i] + a[c] >= l + p) c--;for (int ii = max(i, j) + 1; ii <= n; ii++) {if (a[i] + a[ii] >= p)  break;ans.push_back(a[i] + a[ii]);}for (int ii = max(i, c) + 1; ii <= n; ii++)ans.push_back((a[i] + a[ii]) % p);}while (ans.size() < k)  ans.push_back(r);sort(ans.begin(), ans.end(), greater<int>());for (auto t : ans)  cout << t << ' ';cout << '\n';
}
signed main() {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);int t = 1;cin >> t;while (t--) {solve();}return 0;
}

J Tokitsukaze and Recall

题目描述

在初代《星际争霸》中,神族的仲裁者有“recall”技能,可将一定范围的我方部队从地图任意地点传送到仲裁者所在位置,且仲裁者可部署在任意敌方区域上空,能使用任意次该技能。

Tokitsukaze 玩“岛屿”地图,地图区域不一定连通,敌方占领 n n n 块区域,有 m m m 条双向道路连接不同区域。我方部队可在已占领区域随意移动,但无法穿过敌方占领区域,不过可通过在目标区域部署仲裁者使用“recall”技能将部队传送过去。

Tokitsukaze 有一个无敌地面部队,部队初始在区域 0 0 0(与敌方区域不相连),她只能建造 k k k 个仲裁者,想合理部署以尽可能多地占领敌方区域。要求输出最多能占领的敌方区域数量,以及按占领顺序输出区域编号,若有多种方案,输出字典序最小的那种。

字典序规则:数组 c c c 在字典序上小于数组 d d d 当且仅当以下任一情况成立:

  • ∣ c ∣ < ∣ d ∣ |c| < |d| c<d 并且对于所有 1 ≤ i ≤ ∣ c ∣ 1\leq i\leq |c| 1ic 满足 c i = d i c_i = d_i ci=di,其中 ∣ c ∣ |c| c 表示数组 c c c 的长度;
  • c c c d d d 不同的第一个位置上,数组 c c c 的元素小于数组 d d d 中对应的元素。

输入描述

每个测试文件均包含多组测试数据。第一行输入一个整数 T ( 1 ≤ T ≤ 2 × 1 0 5 ) T(1\leq T\leq 2\times 10^5) T(1T2×105) 代表数据组数,每组测试数据描述如下:

  • 第一行输入三个整数 n , m , k ( 1 ≤ k ≤ n ≤ 2 × 1 0 5 ; 0 ≤ m ≤ min ⁡ { n × ( n − 1 ) 2 , 5 × 1 0 5 } ) n, m, k(1\leq k\leq n\leq 2\times 10^5; 0\leq m\leq \min\{\frac{n\times(n - 1)}{2}, 5\times 10^5\}) n,m,k(1kn2×105;0mmin{2n×(n1),5×105}) 代表地图区域数量、双向道路数量、仲裁者数量。
  • 此后 m m m 行,第 i i i 行输入两个整数 u i , v i ( 1 ≤ u i , v i ≤ n ; u i ≠ v i ) u_i, v_i(1\leq u_i, v_i\leq n; u_i\neq v_i) ui,vi(1ui,vin;ui=vi) 代表第 i i i 条双向道路连接区域 u i u_i ui v i v_i vi。保证不存在重复道路,即每两块区域之间最多只有一条道路直接连接。

除此之外,保证单个测试文件的 n n n 之和不超过 2 × 1 0 5 2\times 10^5 2×105 m m m 之和不超过 5 × 1 0 5 5\times 10^5 5×105

输出描述

对于每一组测试数据,输出两行:

  • 第一行输出一个整数 s ( 1 ≤ s ≤ n ) s(1\leq s\leq n) s(1sn) 代表 Tokitsukaze 最多占领的敌方区域数量。
  • 第二行输出 s s s 个互不相同的整数 c 1 , c 2 , … , c s ( 1 ≤ c i ≤ n ) c_1, c_2, \ldots, c_s(1\leq c_i\leq n) c1,c2,,cs(1cin),第 i i i 个整数 c i c_i ci 表示 Tokitsukaze 第 i i i 次占领的是区域 c i c_i ci。如果有多种方案,输出字典序最小的那种。

示例

示例 1

输入
5
4 3 1
2 1
1 3
3 4
4 3 1
1 3
3 4
4 2
4 3 2
1 3
3 4
4 2
5 3 1
1 2
3 4
4 5
6 4 1
1 2
2 6
3 4
4 5
输出
4
1 2 3 4
4
1 3 4 2
4
1 2 3 4
3
3 4 5
3
1 2 6
说明
  • 对于第一组测试数据:将仅有 1 1 1 个仲裁者部署在区域 1 1 1,Tokitsukaze 将部队传送到区域 1 1 1 并占领;接着让部队到达区域 2 2 2 并占领;接着让部队从区域 2 2 2 回到区域 1 1 1,然后前往区域 3 3 3 并占领;最后让部队从区域 3 3 3 前往区域 4 4 4 并占领。所以占领的顺序是 { 1 , 2 , 3 , 4 } \{1, 2, 3, 4\} {1,2,3,4}
  • 对于第二组测试数据:将仅有 1 1 1 个仲裁者部署在区域 1 1 1,Tokitsukaze 将部队传送到区域 1 1 1 并占领;接着让部队到达区域 3 3 3 并占领;接着让部队从区域 3 3 3 前往区域 4 4 4 并占领;最后让部队从区域 4 4 4 前往区域 2 2 2 并占领。所以占领的顺序是 { 1 , 3 , 4 , 2 } \{1, 3, 4, 2\} {1,3,4,2}
  • 对于第三组测试数据:将 2 2 2 个仲裁者分别部署在区域 1 1 1 和区域 2 2 2
  • 对于第四组测试数据:将 1 1 1 个仲裁者部署在区域 1 1 1 或者区域 2 2 2 只能占领 2 2 2 个敌方区域;而部署在区域 3 3 3 4 4 4 5 5 5 中任意一个区域,均可以占领 3 3 3 个敌方区域,并且部署在区域 3 3 3 可以使占领顺序的区域编号字典序最小,占领的顺序为 { 3 , 4 , 5 } \{3, 4, 5\} {3,4,5}
  • 对于第五组测试数据:将 1 1 1 个仲裁者部署在区域 1 1 1 2 2 2 6 6 6 中任意一个区域可以占领 3 3 3 个敌方区域;部署在区域 3 3 3 4 4 4 5 5 5 中任意一个区域也可以占领 3 3 3 个敌方区域。字典序最小的方案是部署在区域 1 1 1,占领顺序为 { 1 , 2 , 6 } \{1, 2, 6\} {1,2,6}

示例 2

输入
4
4 0 1
4 0 2
4 0 3
4 0 4
输出
1
1
2
1 2
3
1 2 3
4
1 2 3 4

解题思路

整体思路

题目要求访问到的点数最多,并且访问顺序的字典序最小。可以分两步解决:先求出能访问到的最多点数,再考虑访问顺序的字典序最小。

解决点数最多的问题

求出每个连通块有多少个点,并按点的数量从大到小排序。优先选择点数前 k k k 多的连通块;如果 k k k 大于等于连通块个数,则可以全选。

考虑字典序最小

  • 选择连通块时:如果两个连通块的点数相同但只能选一个,设连通块内编号最小的节点的编号为 m n mn mn,在排序时,优先选择 m n mn mn 小的那个连通块。
  • 统计连通块信息:统计连通块内节点个数与最小编号可以建图后使用深度优先搜索(dfs)或者并查集实现。
  • 维护可访问节点:为了使字典序最小,用一个优先队列来维护所有可访问的节点,每次弹出最小编号。
  • 部署仲裁者:因为要求访问顺序字典序最小,所以仲裁者肯定会被部署在一个连通块的编号最小的节点上,即部署在连通块的 m n mn mn 节点。最初,把所有选择的连通块的 m n mn mn 节点都放入优先队列。
  • 处理剩余仲裁者:如果 k k k 大于连通块个数,即 k k k 还有剩余,可以把剩余的 k k k 服务于最小字典序。具体的,如果当前 k > 0 k > 0 k>0,并且存在编号比队列弹出来的编号更小的节点,那么直接在那个节点上部署是更优的。

复杂度分析

由于使用了优先队列,每个节点最多会入队出队一次,所以时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

代码链接

https://ac.nowcoder.com/acm/contest/view-submission?submissionId=75401084

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,f[2000005];
int ver[2000005],Next[2000005],head[2000005],tot;
int fa[2000005],sz[2000005],minn[2000005];
int ans[2000005],num;
struct node
{int mn,sz;
}t[2000005];
int cmp(node a,node b)
{if(a.sz==b.sz)return a.mn<b.mn;return a.sz>b.sz;
}
void add(int x,int y)
{ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
}
int find(int x)
{if(x==fa[x])return fa[x];return fa[x]=find(fa[x]);
}
void merge(int x,int y)
{int t1=find(x),t2=find(y);if(t1!=t2){fa[t2]=t1;sz[t1]+=sz[t2];minn[t1]=min(minn[t1],minn[t2]);}
}
signed main()
{int tt;cin>>tt;while(tt--){int sum=0;tot=0,num=0;int k;cin>>n>>m>>k;for(int i=1;i<=n;i++){fa[i]=i;sz[i]=1;minn[i]=i;}for(int i=1;i<=m;i++){int x,y;cin>>x>>y;add(x,y);add(y,x);merge(x,y);}int cnt=0;map<int,int>mp;for(int i=1;i<=n;i++){if(!mp[find(i)]){t[++cnt].mn=minn[find(i)];t[cnt].sz=sz[find(i)];mp[find(i)]=1;}}sort(t+1,t+cnt+1,cmp);priority_queue<int>q;map<int,int>v;for(int i=1;i<=min(k,cnt);i++){sum+=t[i].sz;q.push(-t[i].mn);v[t[i].mn]=1;}if(k>=cnt)k-=cnt;elsek=0;int mex=1;while(q.size()){int u=-q.top();q.pop();ans[++num]=u;for(int i=head[u];i;i=Next[i]){int y=ver[i];if(!v[y]){q.push(-y);v[y]=1;}}if(k){int p=-q.top();if(p!=u+1){v[u+1]=1;q.push(-u-1);k--;}}}cout<<sum<<endl;for(int i=1;i<=sum;i++){cout<<ans[i]<<" ";}cout<<endl;for(int i=0;i<=n;i++){head[i]=0;ans[i]=0;t[i].sz=0;t[i].mn=0;}}return 0;
}

http://www.ppmy.cn/ops/157413.html

相关文章

2025.1.8(qt图形化界面之消息框)

笔记&#xff08;后期复习补充&#xff09; 作业 1> 手动将登录项目实现&#xff0c;不要使用拖拽编程 并且&#xff0c;当点击登录按钮时&#xff0c;后台会判断账号和密码是否相等&#xff0c;如果相等给出登录成功的提示&#xff0c;并且关闭当前界面&#xff0c;发射一…

‌双非硕士的抉择:自学嵌入式硬件开发还是深入Linux C/C++走软开?

今天给大家分享的是一位粉丝的提问&#xff0c;双非硕研一是自学嵌入式走偏硬件还是说深入学习Linuxc/c走软开呢&#xff1f; 接下来把粉丝的具体提问和我的回复分享给大家&#xff0c;希望也能给一些类似情况的小伙伴一些启发和帮助。 粉丝提问&#xff1a; 老师好&#xff…

【DeepSeek论文翻译】DeepSeek-R1: 通过强化学习激励大型语言模型的推理能力

目录 摘要 1. 引言 2. 方法 2.1. 概述 2.2. DeepSeek-R1-Zero&#xff1a;在基础模型上进行强化学习 2.2.1. 强化学习算法 2.2.2. 奖励建模 2.2.3. 训练模板 2.2.4. DeepSeek-R1-Zero 的性能、自我进化过程和顿悟时刻 2.3. DeepSeek-R1&#xff1a;具有冷启动的强化学…

游戏引擎学习第90天

查看我们现在的进度 目标是完整地手写一个游戏&#xff0c;而不依赖任何现有的游戏引擎或库。这样做的主要原因是希望能够从头到尾掌握游戏开发的全部流程&#xff0c;确保对系统的每个部分都有清晰的理解。此外&#xff0c;现有的引擎和库往往存在各种设计上的问题&#xff0…

WordPress wp-recall插件存在SQL注入漏洞(CVE-2024-32709)

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…

Linux进阶——web服务器

一、相关名词解释及概念&#xff1a; www&#xff1a;(world wide web)全球信息广播&#xff0c;通常来说的上网就是使用www来查询用户所需的信息。使用http超文本传输协议。 过程&#xff1a;web浏览器向web服务&#xff08;Apache&#xff0c;Microsoft&#xff0c;nginx&…

【IoCDI】_@Autowired存在的问题及解决

目录 1. Autowired存在问题 2. 解决方法 2.1 方法1&#xff1a;属性名与需要使用的对象名保持一致 2.2 方法2&#xff1a;使用Primary指定要使用的对象 2.3 方法3&#xff1a;使用Qualifier指定要使用的对象 2.4 方法4&#xff1a;使用Resource指定要使用的对象 3. 关于…

Java 读取 PDF 模板文档并替换内容重新生成 PDF

朋友们&#xff01;在实际开发里&#xff0c;经常会遇到需要根据 PDF 模板文档生成特定 PDF 的需求&#xff0c;比如合同、证书等。咱们可以借助 iText 库来实现读取 PDF 模板文档、替换指定内容&#xff0c;最后重新生成新 PDF 的功能。下面我就详细给大家讲讲具体怎么做。 1.…