标签:例子 gis += return cal begin pac 方法 namespace
给定长度为 \(N\) 的数列 \(A\),对于 \(X=1,2...K\) 计算:
\(N\le 2\times 10^5,K\le 300\)
考虑二项式定理:
预处理 \(\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 ;
}
有 \(n\) 个工人,第 \(i\) 个人第 \([1,A_i]\) 天工作,第 \([A_i+1,2A_i]\) 休息,然后 \([2A_i+1,3A_i]\) 工作,依次类推。
你需要给这些工人发工资,使得所有工人都至少领到了 \(K\) 个硬币,规则是你每天可以选择一个在工作的工人发一枚硬币。
求最少多少天可以发完。
\(N\le 18,K\le 10^5,A_i\le 10^5\)
我们发现答案的下界是 \(NK\)
我们发现我们存在一种 \(2NK\) 级的策略,就是一个人一个人的发完,显然这个策略的答案是 \(2NK\) 这个级别的。
当然,显然我们可以更优的给硬币,我们可以猜测答案的上界是 \(2NK\)
同时不难给出 \(2NK\) 的例子,即所有 \(A_i\) 相同。
考虑二分答案,然后这个模型非常像网络流问题,考虑暴力网络流建模:
此时,如果这张图流量为 \(NK\) 就说明合法。
不难注意到有不少天 \(i\) 和 \(j\) 的连边是相似的,我们可以将他们压缩到一起,因为本质不同的连边只有 \(2^n\) 种(即这一天连向所有人的可能的情况)
此时这张图为二分图,暴力 dinic 的复杂度为 \(\mathcal O(M\sqrt{N})\) 近似于 \(n\cdot 2^{\frac{3}{2}n}\) 这个级别。
我们肯定不是暴力网络流,考虑最大流等于最小割,我们考虑这张图的最小割。
我们发现这张二分图的 \(T\) 边的节点数只有 \(N\) 个,而 \(S\) 边有 \(2^N\) 个,同时 \(S\) 边的每个节点均为一个状态,它只会向 \(T\) 边此位为 \(1\) 的点连边。
考虑枚举 \(T\) 边的割边情况,此时另一边不用被割去的边仅有此边对应的状态为它的子集的情况。那么可以使用高维前缀和/FMT来进行预处理,然后取 \(\min\) 来得到最小割即可,如果最小割为 \(NK\) 就说明合法。
复杂度为 \(\mathcal O(N^2K+N2^N\log (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 ;
}
给定 \(n\) 个机器人,第 \(i\) 个机器人有 \(d_i\) 个接口。
你需要将机器人连接成树,方法为分别选定两个不同的机器人的一个未被选择的接口,然后连接这两个机器人。
求本质不同的树的数量,其中连接的接口不同视为树不同。
答案对 \(998244353\) 取模。
\(N\le 2\times 10^5,d_i<998244353\)
考虑这 \(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}]=\binom{k}{z}\)。
设 \(D=\sum d_i,N\leftarrow 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 ;
}
标签:例子 gis += return cal begin pac 方法 namespace
原文地址:https://www.cnblogs.com/Soulist/p/13872450.html