ARC106 选做
Posted soulist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARC106 选做相关的知识,希望对你有一定的参考价值。
ARC106 选做
ARC106D [* easy]
给定长度为 (N) 的数列 (A),对于 (X=1,2...K) 计算:
(Nle 2 imes 10^5,Kle 300)
Solution
考虑二项式定理:
预处理 (sum A_i^k),设为 (S_k),答案可以表示为:
(mathcal O(NK)) 的预处理,然后 (mathcal O(K^2)) 的 count 即可,复杂度 (mathcal O(NK+K^2))
(Code:)
#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int long long
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < ‘0‘ || cc > ‘9‘ ) { if( cc == ‘-‘ ) flus = - flus ; cc = getchar() ; }
while( cc >= ‘0‘ && cc <= ‘9‘ ) cn = cn * 10 + cc - ‘0‘, cc = getchar() ;
return cn * flus ;
}
const int P = 998244353 ;
const int N = 2e5 + 5 ;
const int M = 300 + 5 ;
int fpow(int x, int k) {
int ans = 1, base = x ;
while(k) {
if(k & 1) ans = 1ll * ans * base % P ;
base = 1ll * base * base % P, k >>= 1 ;
} return ans ;
}
int n, m, C[M][M], a[N], S[M], f[M], I ;
signed main()
{
n = gi(), m = gi() ;
rep( i, 1, n ) a[i] = gi() ;
C[0][0] = 1 ;
rep( i, 1, m ) rep( j, 0, i )
C[i][j] = (!j) ? 1 : (C[i - 1][j - 1] + C[i - 1][j]) % P ;
S[0] = n, f[0] = n ;
rep( i, 1, n ) {
int z = 1, t = 1 ;
rep( j, 1, m )
z = z * a[i] % P, t = t * (a[i]) * 2 % P,
S[j] = (S[j] + z) % P, f[j] = (f[j] + t) % P ;
}
I = (P + 1) / 2 ;
rep( i, 1, m ) {
int Ans = 0 ;
rep( j, 0, i ) Ans = (Ans + C[i][j] * S[j] % P * S[i - j] % P) % P ;
Ans = (Ans - f[i] + P) % P ;
cout << Ans * I % P << endl ;
}
return 0 ;
}
ARC106E [* easy]
有 (n) 个工人,第 (i) 个人第 ([1,A_i]) 天工作,第 ([A_i+1,2A_i]) 休息,然后 ([2A_i+1,3A_i]) 工作,依次类推。
你需要给这些工人发工资,使得所有工人都至少领到了 (K) 个硬币,规则是你每天可以选择一个在工作的工人发一枚硬币。
求最少多少天可以发完。
(Nle 18,Kle 10^5,A_ile 10^5)
Solution
我们发现答案的下界是 (NK)
我们发现我们存在一种 (2NK) 级的策略,就是一个人一个人的发完,显然这个策略的答案是 (2NK) 这个级别的。
当然,显然我们可以更优的给硬币,我们可以猜测答案的上界是 (2NK)
同时不难给出 (2NK) 的例子,即所有 (A_i) 相同。
考虑二分答案,然后这个模型非常像网络流问题,考虑暴力网络流建模:
- 从源点 (S) 连向每天 (i) 一点流量。
- 从每个人 (j o T),(K) 点流量。
- 每天向这一天在工作的每个人连向 (infty) 的流量。
此时,如果这张图流量为 (NK) 就说明合法。
不难注意到有不少天 (i) 和 (j) 的连边是相似的,我们可以将他们压缩到一起,因为本质不同的连边只有 (2^n) 种(即这一天连向所有人的可能的情况)
此时这张图为二分图,暴力 dinic 的复杂度为 (mathcal O(Msqrt{N})) 近似于 (ncdot 2^{frac{3}{2}n}) 这个级别。
我们肯定不是暴力网络流,考虑最大流等于最小割,我们考虑这张图的最小割。
我们发现这张二分图的 (T) 边的节点数只有 (N) 个,而 (S) 边有 (2^N) 个,同时 (S) 边的每个节点均为一个状态,它只会向 (T) 边此位为 (1) 的点连边。
考虑枚举 (T) 边的割边情况,此时另一边不用被割去的边仅有此边对应的状态为它的子集的情况。那么可以使用高维前缀和/FMT来进行预处理,然后取 (min) 来得到最小割即可,如果最小割为 (NK) 就说明合法。
复杂度为 (mathcal O(N^2K+N2^Nlog (NK)))
其中 (N^2K) 为预处理每个时间点对应的状态的复杂度。
(Code:)
#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define Rep( i, s, t ) for( register int i = (s); i < (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < ‘0‘ || cc > ‘9‘ ) { if( cc == ‘-‘ ) flus = - flus ; cc = getchar() ; }
while( cc >= ‘0‘ && cc <= ‘9‘ ) cn = cn * 10 + cc - ‘0‘, cc = getchar() ;
return cn * flus ;
}
const int N = (1 << 18) + 5 ;
const int M = 5e6 + 5 ;
int n, K, A[20], lim, limit, sta[M] ;
int f[N] ;
int bit(int x) {
return __builtin_popcount(x) ;
}
bool check(int x) {
limit = (1 << n) - 1 ;
rep( i, 0, limit ) f[i] = 0 ;
rep( i, 1, x ) ++ f[sta[i]] ;
int ans = n * K ;
for(re int k = 1; k <= limit; k <<= 1)
rep( i, 0, limit ) if(i & k) f[i] += f[i ^ k] ;
for(re int i = 0; i <= limit; ++ i)
ans = min( bit(i) * K + f[limit] - f[i], ans ) ;
return (ans == n * K) ;
}
signed main()
{
n = gi(), K = gi(), lim = 2 * n * K ;
Rep( i, 0, n ) A[i] = gi() ;
rep( i, 1, lim ) Rep( j, 0, n )
if(!(((i - 1) / A[j]) & 1)) sta[i] |= (1 << j) ;
int l = 0, r = lim, ans = 0 ;
while( l <= r ) {
int mid = (l + r) >> 1 ;
if(check(mid)) ans = mid, r = mid - 1 ;
else l = mid + 1 ;
}
cout << ans << endl ;
return 0 ;
}
ARC106F [* easy]
给定 (n) 个机器人,第 (i) 个机器人有 (d_i) 个接口。
你需要将机器人连接成树,方法为分别选定两个不同的机器人的一个未被选择的接口,然后连接这两个机器人。
求本质不同的树的数量,其中连接的接口不同视为树不同。
答案对 (998244353) 取模。
(Nle 2 imes 10^5,d_i<998244353)
Solution
考虑这 (n) 个机器人生成的树,假设此树上机器人 (i) 的度数为 (c_i),那么贡献为 (d_i^{underline{c_i}})(考虑给边标号,然后再任意排布)
现在从 prufer 序列的角度来考虑答案,由于每个点的度数都是出现次数 (+1),方便起见我们给答案乘以 (prod d_i),然后给 (d_i-1),现在需要统计长度为 (N-2) 的序列的所有贡献和。
使用 EGF 刻画答案,我们不难发现:
即为答案。
考虑前半部分:
((1+x)^{k}[x^{z}]=inom{k}{z})。
设 (D=sum d_i,Nleftarrow N-2,M=sum d_i),我们有答案即为:
这样就避免了分母为 (0) 的问题了。
(Code:)
#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int long long
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < ‘0‘ || cc > ‘9‘ ) { if( cc == ‘-‘ ) flus = - flus ; cc = getchar() ; }
while( cc >= ‘0‘ && cc <= ‘9‘ ) cn = cn * 10 + cc - ‘0‘, cc = getchar() ;
return cn * flus ;
}
const int P = 998244353 ;
int fpow(int x, int k) {
int ans = 1, base = x ;
while(k) {
if(k & 1) ans = 1ll * ans * base % P ;
base = 1ll * base * base % P, k >>= 1 ;
} return ans ;
}
int n, D, M ;
signed main()
{
n = gi() ; int x ; M = 1 ;
rep( i, 1, n ) x = gi(), D = (D + x - 1) % P, M = M * x % P ;
n -= 2 ;
rep( i, 1, n ) M = M * (D - i + 1) % P ;
cout << M << endl ;
return 0 ;
}
以上是关于ARC106 选做的主要内容,如果未能解决你的问题,请参考以下文章