比赛链接:VIP专享
T1
场切了,随便猜......
T2
被 hack 了......
逻辑错误在于,在枚举"最早全 1 的行"时,把 "该行对应列初始没有 1" 错误地当成该行不可选的否决条件而直接放弃,而正确做法是只需额外加 1 次操作,并且我还错误地用了 vis[i] 去判断每个 0,导致漏解。
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 3005;
int n, c[N][N];
string s;
bool vis[N];
int rowOnes[N];
signed main(){
freopen("fountain.in", "r", stdin);
freopen("fountain.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++){
cin >> s;
for (int j = 1; j <= n; j++){
c[i][j] = s[j - 1] - '0';
if (c[i][j] == 1){
vis[j] = true;
rowOnes[i]++;
}
}
}
bool allOne = true;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
if (c[i][j] != 1){
allOne = false;
break;
}
}
if (!allOne)
break;
}
if (allOne){
cout << 0;
return 0;
}
int cnt = 0;
for (int j = 1; j <= n; j++){
bool flag = true;
for (int i = 1; i <= n; i++){
if (c[i][j] == 0){
flag = false;
break;
}
}
if (flag){
cnt++;
}
}
for (int i = 1; i <= n; i++){
if (rowOnes[i] == n){
cout << n - cnt;
return 0;
}
}
int ans = 0x3f3f3f3f;
for (int i = 1; i <= n; i++){
int cur = (n - rowOnes[i]) + (n - cnt);
if (!vis[i])
cur++;
ans = min(ans, cur);
}
cout << ans;
return 0;
}
T3
其实场上想出来了一个两次 hxf 容斥 + 插板的东西,但是,第一,复杂度是错的,不是正解,另一方面,被 l y x lyx lyx 证明为假。
但是倒是有一些不错的试探。
我们来看一下题解。
不妨设前 n n n 个数的和为 A A A,后 n n n 个数的和为 B B B,那么,我们所求的可以转化为 1 − P ( A = B ) 2 ( m o d P ) \dfrac{1-P(A=B)}{2}(\mod P) 21−P(A=B)(modP)。
我可能也想到了 50 p t s 50pts 50pts 做法吗?就是打一个 DP,随便做一做......
插板+容斥是对的😭
我们发现,由于要求两端和相等,不妨将后半段的取值看作 − m , 0 -m,0 −m,0,统一加上 m m m 之后,就是要求整段和为 n × m n\times m n×m 的值。
我么发现这个是经典的插板法+容斥,直接出式子:
E = ∑ k = 0 n − 1 ( − 1 ) k × C 2 n k × C n m − k × ( m + 1 ) + 2 n − 1 2 n − 1 E=\sum\limits_{k=0}^{n-1}{(-1)^k\times C_{2n}^{k}\times C_{nm-k\times(m+1)+2n-1}^{2n-1}} E=k=0∑n−1(−1)k×C2nk×Cnm−k×(m+1)+2n−12n−1
我们来解释一下这个公式,就是说,如果没有 0 , m 0,m 0,m 的限制,那么,我们直接插板就行,及 C n m + 2 n − 1 2 n − 1 C_{nm+2n-1}^{2n-1} Cnm+2n−12n−1,为什么要加一个 2 n − 1 2n-1 2n−1 呢?就是因为可以取到 0 0 0,即板可以重复放在一个位置。
那么,我们枚举的是什么呢?上面考虑的是无限制的,此时,我们需要考虑 0 , m 0,m 0,m 这一限制,即我们枚举有 k k k 个超出了限制,然后减去一些总板数,从所有的挑出来,再容斥一发,就做完了!
a n s = 1 − E ( m + 1 ) 2 n 2 ans=\dfrac{1-\frac{E}{(m+1)^{2n}}}{2} ans=21−(m+1)2nE
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5000005;
int P, T, n, m;
int fac[N], inv[N];
int qpow(int a, int b){
int res = 1;;
while (b){
if (b & 1)
res = res * a % P;
a = a * a % P;
b >>= 1;
}
return res;
}
int C(int n, int m){
if (n < 0 || m < 0 || m > n)
return 0;
return fac[n] * inv[n - m] % P * inv[m] % P;
}
signed main(){
freopen("pr.in", "r", stdin);
freopen("pr.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> P;
cin >> T;
fac[0] = 1;
for (int i = 1; i < N; i++){
fac[i] = fac[i - 1] * i % P;
}
inv[N - 1] = qpow(fac[N - 1], P - 2);
for (int i = N - 2; i >= 0; i--){
inv[i] = inv[i + 1] * (i + 1) % P;
}
for (int cs = 1; cs <= T; cs++){
cin >> n >> m;
int E = 0;
for (int k = 0; k < n; k++){
E = (E + qpow(-1, k) * C(2 * n, k) % P * C(n * m - k * (m + 1) + (2 * n - 1), 2 * n - 1) % P) % P;
}
cout << (1 - E * qpow(qpow(m + 1, 2 * n), P - 2) % P + P) * qpow(2, P - 2) % P << '\n';
}
}
T4
这个不补了,天天扔这种东西......