C 题没开 long long
见了祖宗。
D - Sky Reflector
在一个 (n imes m) 的矩阵中填数,每个格子填 (1leq xleq k) ,设 (A_i) 是行最小值,(B_i) 是列最大值。求可能的 ((A,B)) 序列个数。对 (998244353) 取模。
如果 (n=1) 或者 (m=1) ,那么直接就是 (k^m) 或者 (k^n) .
对于剩下的情况,设 (A_1) 为 (max{A_i}) ,(B_1) 为 (min{B_i}) 。下面构造一种方案,使得满足上述条件,且 (A_1leq B_1) 的 (A,B) 序列均可以取到。
放置方案如下:
- (A_1,B_1,A_2,B_2) :((1,1),(2,1),(2,2),(1,2))
- (A_i,B_i) :((i,1),(1,i)) ( (ige 3) )
- 其余:对于第 (i) 行的元素,令其等于 (A_i) .
不难发现这个构造一定是合法的。然后只需要对满足条件的 (A_1,B_1) 计数即可。
枚举 (A_1) ,设为 (x) ,那么 (A) 序列的方案数是 (x^n-(x-1)^n) ,减去没出现 (x) 的情况;(B) 序列的方案数是 ((k-x+1)^m) ,最小值 (B_1ge A_1) 。
//Author: RingweEH
void bmod( int &x,int y ) { x+=y-Mod; x+=(x<0)*Mod; }
int n,m,k;
int main()
{
n=read(); m=read(); k=read();
if ( n==1 ) { printf("%d
",power(k,m) ); return 0; }
if ( m==1 ) { printf("%d
",power(k,n) ); return 0; }
int ans=0;
for ( int i=1; i<=k; i++ )
{
int t1=power(i,n); bmod( t1,Mod-power(i-1,n) );
int t2=k-i+1; t2=power(t2,m);
bmod(ans,1ll*t1*t2%Mod);
}
printf("%d
",ans );
return 0;
}
E - Rvom and Rsrev
给定一个由 a
b
组成的字符串 (S) ,求能得到的字典序最大的字符串。每次操作可以:
- 选择两个 (S) 中相同的字符,将这两个字符中间的一段反转,然后删去这两个字符。
字符串总长 (leq 2e5) .
极速爪巴。这分讨太 /tuu
了…… 是我见过最长的AT题解 Official 翻译官已上线。
设定:(S) 有 (C_a) 个 a
,(C_b) 个 b
.
S 结尾为 a
令 (k) 为 (S) 结尾最长的连续 a
串的起始位置,并令 (S_0) 为 b
.
通过以下操作可以使 (S) 中 (C_b) 个 b
全部在开头:
- 如果存在 (i) 使得 (1leq i<k) ,(S_{i-1}) =
b
,(S_{i}) =a
,(S_{i+1}) =a
,那么操作 ((i,k)) ( (k) 前面一个必然是b
) - 否则,如果存在多个 (1leq i<k) 使得 (S_{i-1}) =
b
,(S_{i}) =a
,(S_{i+1}) =b
, 选择其中任意两个操作(目的是删去a
) - 否则,如果存在 (i<k) 使得 (S_i) =
a
,操作 ((i,k)) . - 否则结束。
(前两个操作确保 (S) 的结尾仍然是 a
)
为了使得字典序最大,需要找到 (t_{max}) 使得 (S) = bb...baa...a
( (C_b) 个 b
和 (t) 个 a
)。最大化 (t) 就是最小化操作次数。下面证明上面的操作最优。
设有 (x) 个 a
子串和 (y) 个 bb
子串(除了 (S) 末尾连续的全 a
串以外)。定义 (S) 的 势 (phi(S)) 为 (x+2y) .
那么,不难发现,任意一次对两个 a
的操作使得 (phi(S)) 减少至多 (2) ,而希望得到的 (phi) 是 (0) ,所以有至少 (lceilphi(S)/2
ceil) 次操作。上面构造的前两个操作使得 (phi) 每次减少 (2) ,第三个操作最多执行一次,因此这种方式达到了这个下界。
S 结尾为 b
- 如果 (C_a) 是偶数
重复对两个 a
操作,可以使得 (S) = bb..b
( (C_b) 个),且不可能把 a
放到末尾,因此答案就是 bb..b
.
- 如果 (C_a) 是奇数且 (S) 结尾是
ab
依然重复操作 a
,可以将 (S) 变为 bb..bab
的形式。不删除 b
,也无法移动 a
,所以这就是答案。
- (C_a) 为奇数,(S) 结尾
abb
重复操作不在结尾的 a
,变成 bb..bab
的形式。同理这个也是最大值。
- (C_a) 为奇数,(S) 结尾
bbb
如果 (S) = aa..abb..b
,答案就是 abb..b
。
否则,可以通过如下(至多一次)操作将 a
移到 (S) 末尾:
- 如果存在 (1leq ileq |S|-2) 使得 (S_i) =
b
,(S_{i+1}) =a
,(S_{i+2}) =a
,操作 ((i,|S|)) (操作 A ) - 否则,选择一个 (1leq ileq |S|-2) 使得 (S_i) =
b
,(S_{i+1}) =a
,(S_{i+2}) =b
,操作 ((i,|S|)) (操作 B )
然后 (S) 开头就是 (C_b-2) 个 b
,显然不可能更大。
现在证明上面的操作最大化了结尾的 a
的个数,同样转化为最小化操作,并定义势。
为了让 a
到末尾,需要操作结尾的 b
,这个操作至多使 (phi) 减少 (2) ,且为了保持 b
的个数,这个操作至多一次。所以任何操作至多使得 (phi) 减少 (2) ,且我们需要 (lceilphi(S)/2
ceil) 次操作。
如果存在 (1leq ileq |S|-2) 使得 (S_i) = b
,(S_{i+1}) = a
,(S_{i+2}) = a
,A 操作使得 (phi) 减少 (2) 。否则,操作 B 使得 (phi) 减少 (1) . 因此,如果 (phi) 初始为奇数,那么我们可以通过上面的操作得到最大值。这种情况下,一共做了 (phi/2+1) 次操作,我们需要证明不可能在 (phi(S)/2) 次操作内完成(这种情况下每个操作都要使得 (phi-=2) )
(S) 中对 a
的操作如下:
- 对 (S) 开头连续的
a
操作,(phi) 至多减少 (1) - 对一个开头连续的
a
和一个后面的a
操作,(phi) 只有在开头连续a
的个数不大于 (2) 的情况下才会减少 (2) ,但是这样的操作不会使得新的满足 A 操作的 (1leq i) 出现。 - 对两个不在开头连续
a
的a
操作,不会让新的满足 A 操作条件的 (i) 出现。
所以 (phi/2) 次操作是不可能的。
//Author: RingweEH
void Task1()
{
int c1=0,c2=0,c3=0; //baa,bab,a
for ( int i=1; i<=n; i++ )
if ( s[i]=='a' ) c3++;
else
{
if ( c3==1 ) c2++;
if ( c3>1 ) c1++;
c3=0;
}
int x=c1+(c2+1)/2;
for ( int i=1; i<=cntb; i++ ) putchar('b');
for ( int i=1; i<=cnta-2*x; i++ ) putchar('a');
puts("");
}
void Task2()
{
for ( int i=1; i<=cntb; i++ ) putchar('b'); puts("");
}
void Task3( int x )
{
for ( int i=1; i<=cntb-x; i++ ) putchar('b');
putchar('a');
for ( int i=1; i<=x; i++ ) putchar('b');
puts("");
}
void Task4()
{
int pos=-1;
for ( int i=1; i<=n-3; i++ ) if ( s[i]=='b' && s[i+1]=='a' && s[i+2]=='a' ) pos=i;
if ( pos==-1 )
for ( int i=1; i<=n-3; i++ )
if ( s[i]=='b' && s[i+1]=='a' && s[i+2]=='b' ) { pos=i; break; }
if ( pos==-1 ) { putchar('a'); for ( int i=1; i<=cntb; i++ ) putchar('b'); puts(""); }
else
{
reverse(s+1+pos,s+n);
for ( int i=pos; i<=n-2; i++ ) s[i]=s[i+1];
n-=2; cntb-=2; Task1();
}
}
int main()
{
int T; scanf( "%d",&T );
while ( T-- )
{
scanf( "%s",s+1 ); n=strlen(s+1);
cnta=cntb=0;
for ( int i=1; i<=n; i++ ) (s[i]=='a') ? cnta++ : cntb++;
if ( s[n]=='a' ) Task1();
else if ( cnta%2==0 ) Task2();
else if ( s[n-1]=='a' ) Task3(1);
else if ( s[n-2]=='a' ) Task3(2);
else Task4();
}
return 0;
}
F - Social Distance
给定一个长度为 (n+1) 的序列 (X) ,满足 (0=X_0<X_1<cdots<X_N) .
(n) 个人站在数轴上,第 (i) 个人的位置在 ([X_{i-1},X_i]) 区间的一个随机实数点上。求两两之间最短距离的期望。
这是什么毒瘤场 /tuu
只有两个场上只写了 F 的老哥过 F 了,所有人都到 E 戛然而止 /jk
话虽如此 ABCD 还是很清新的说……
咕咕咕.